mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2025-10-03 01:39:31 +02:00
Retry transactions
This commit is contained in:
parent
9b8caccfbd
commit
f5198c7c0b
2 changed files with 45 additions and 7 deletions
|
@ -42,6 +42,7 @@ import { createU2fKeyModel, U2fKeyModelStatic } from './u2fkey'
|
|||
import { createUsedTimeModel, UsedTimeModelStatic } from './usedtime'
|
||||
import { createUserModel, UserModelStatic } from './user'
|
||||
import { createUserLimitLoginCategoryModel, UserLimitLoginCategoryModelStatic } from './userlimitlogincategory'
|
||||
import { shouldRetryWithException } from './utils/serialized'
|
||||
|
||||
export type Transaction = Sequelize.Transaction
|
||||
|
||||
|
@ -71,10 +72,18 @@ export interface Database {
|
|||
usedTime: UsedTimeModelStatic
|
||||
user: UserModelStatic
|
||||
userLimitLoginCategory: UserLimitLoginCategoryModelStatic
|
||||
transaction: <T> (autoCallback: (t: Transaction) => Promise<T>, options?: { transaction: Transaction }) => Promise<T>
|
||||
transaction: <T> (
|
||||
autoCallback: (t: Transaction) => Promise<T>,
|
||||
options?: TransactionOptions
|
||||
) => Promise<T>
|
||||
dialect: string
|
||||
}
|
||||
|
||||
interface TransactionOptions {
|
||||
transaction?: Transaction
|
||||
disableRetry?: boolean
|
||||
}
|
||||
|
||||
const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
||||
addDeviceToken: createAddDeviceTokenModel(sequelize),
|
||||
authtoken: createAuthtokenModel(sequelize),
|
||||
|
@ -101,10 +110,39 @@ const createDatabase = (sequelize: Sequelize.Sequelize): Database => ({
|
|||
usedTime: createUsedTimeModel(sequelize),
|
||||
user: createUserModel(sequelize),
|
||||
userLimitLoginCategory: createUserLimitLoginCategoryModel(sequelize),
|
||||
transaction: <T> (autoCallback: (transaction: Transaction) => Promise<T>, options?: { transaction: Transaction }) => (sequelize.transaction({
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
||||
transaction: options?.transaction
|
||||
}, autoCallback)) as Promise<T>,
|
||||
async transaction<T>(
|
||||
autoCallback: (transaction: Transaction) => Promise<T>,
|
||||
options?: TransactionOptions
|
||||
): Promise<T> {
|
||||
const runAttempt = () => sequelize.transaction({
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
||||
transaction: options?.transaction
|
||||
}, autoCallback)
|
||||
|
||||
const delay = (time: number) => new Promise((resolve) => setTimeout(resolve, time))
|
||||
|
||||
try {
|
||||
return await runAttempt()
|
||||
} catch (ex) {
|
||||
if (
|
||||
options?.disableRetry ||
|
||||
options?.transaction ||
|
||||
!shouldRetryWithException(this, ex)
|
||||
) throw ex
|
||||
}
|
||||
|
||||
await delay(10 * (1 + Math.random()))
|
||||
|
||||
try {
|
||||
return await runAttempt()
|
||||
} catch (ex) {
|
||||
if (!shouldRetryWithException(this, ex)) throw ex
|
||||
}
|
||||
|
||||
await delay(100 * (1 + Math.random()))
|
||||
|
||||
return await runAttempt()
|
||||
},
|
||||
dialect: sequelize.getDialect()
|
||||
})
|
||||
|
||||
|
|
|
@ -86,8 +86,8 @@ export async function assertSerializeableTransactionsAreWorking (database: Datab
|
|||
await database.config.update({ value: 'd' }, { where: { id: configItemIds.secondSelfTestData }, transaction: transactionTwo })
|
||||
})()
|
||||
])
|
||||
})
|
||||
})
|
||||
}, { disableRetry: true })
|
||||
}, { disableRetry: true })
|
||||
|
||||
throw new SerializationFeatureCheckException()
|
||||
} catch (ex) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue