try catch around semaphore lock

This commit is contained in:
Ulf Gebhardt 2023-01-16 11:04:14 +01:00
parent e59d2f0a0e
commit dab7fe584a
Signed by: ulfgebhardt
GPG Key ID: DA6B843E748679C9

View File

@ -170,148 +170,151 @@ export class TransactionLinkResolver {
if (code.match(/^CL-/)) { if (code.match(/^CL-/)) {
// acquire lock // acquire lock
const releaseLock = await TRANSACTIONS_LOCK.acquire() const releaseLock = await TRANSACTIONS_LOCK.acquire()
logger.info('redeem contribution link...')
const now = new Date()
const queryRunner = getConnection().createQueryRunner()
await queryRunner.connect()
await queryRunner.startTransaction('REPEATABLE READ')
try { try {
const contributionLink = await queryRunner.manager logger.info('redeem contribution link...')
.createQueryBuilder() const now = new Date()
.select('contributionLink') const queryRunner = getConnection().createQueryRunner()
.from(DbContributionLink, 'contributionLink') await queryRunner.connect()
.where('contributionLink.code = :code', { code: code.replace('CL-', '') }) await queryRunner.startTransaction('REPEATABLE READ')
.getOne() try {
if (!contributionLink) { const contributionLink = await queryRunner.manager
logger.error('no contribution link found to given code:', code) .createQueryBuilder()
throw new Error('No contribution link found') .select('contributionLink')
} .from(DbContributionLink, 'contributionLink')
logger.info('...contribution link found with id', contributionLink.id) .where('contributionLink.code = :code', { code: code.replace('CL-', '') })
if (new Date(contributionLink.validFrom).getTime() > now.getTime()) { .getOne()
logger.error( if (!contributionLink) {
'contribution link is not valid yet. Valid from: ', logger.error('no contribution link found to given code:', code)
contributionLink.validFrom, throw new Error('No contribution link found')
)
throw new Error('Contribution link not valid yet')
}
if (contributionLink.validTo) {
if (new Date(contributionLink.validTo).setHours(23, 59, 59) < now.getTime()) {
logger.error('contribution link is depricated. Valid to: ', contributionLink.validTo)
throw new Error('Contribution link is depricated')
} }
} logger.info('...contribution link found with id', contributionLink.id)
let alreadyRedeemed: DbContribution | undefined if (new Date(contributionLink.validFrom).getTime() > now.getTime()) {
switch (contributionLink.cycle) { logger.error(
case ContributionCycleType.ONCE: { 'contribution link is not valid yet. Valid from: ',
alreadyRedeemed = await queryRunner.manager contributionLink.validFrom,
.createQueryBuilder() )
.select('contribution') throw new Error('Contribution link not valid yet')
.from(DbContribution, 'contribution') }
.where('contribution.contributionLinkId = :linkId AND contribution.userId = :id', { if (contributionLink.validTo) {
linkId: contributionLink.id, if (new Date(contributionLink.validTo).setHours(23, 59, 59) < now.getTime()) {
id: user.id, logger.error('contribution link is depricated. Valid to: ', contributionLink.validTo)
}) throw new Error('Contribution link is depricated')
.getOne()
if (alreadyRedeemed) {
logger.error(
'contribution link with rule ONCE already redeemed by user with id',
user.id,
)
throw new Error('Contribution link already redeemed')
} }
break
} }
case ContributionCycleType.DAILY: { let alreadyRedeemed: DbContribution | undefined
const start = new Date() switch (contributionLink.cycle) {
start.setHours(0, 0, 0, 0) case ContributionCycleType.ONCE: {
const end = new Date() alreadyRedeemed = await queryRunner.manager
end.setHours(23, 59, 59, 999) .createQueryBuilder()
alreadyRedeemed = await queryRunner.manager .select('contribution')
.createQueryBuilder() .from(DbContribution, 'contribution')
.select('contribution') .where('contribution.contributionLinkId = :linkId AND contribution.userId = :id', {
.from(DbContribution, 'contribution')
.where(
`contribution.contributionLinkId = :linkId AND contribution.userId = :id
AND Date(contribution.confirmedAt) BETWEEN :start AND :end`,
{
linkId: contributionLink.id, linkId: contributionLink.id,
id: user.id, id: user.id,
start, })
end, .getOne()
}, if (alreadyRedeemed) {
) logger.error(
.getOne() 'contribution link with rule ONCE already redeemed by user with id',
if (alreadyRedeemed) { user.id,
logger.error( )
'contribution link with rule DAILY already redeemed by user with id', throw new Error('Contribution link already redeemed')
user.id, }
) break
throw new Error('Contribution link already redeemed today') }
case ContributionCycleType.DAILY: {
const start = new Date()
start.setHours(0, 0, 0, 0)
const end = new Date()
end.setHours(23, 59, 59, 999)
alreadyRedeemed = await queryRunner.manager
.createQueryBuilder()
.select('contribution')
.from(DbContribution, 'contribution')
.where(
`contribution.contributionLinkId = :linkId AND contribution.userId = :id
AND Date(contribution.confirmedAt) BETWEEN :start AND :end`,
{
linkId: contributionLink.id,
id: user.id,
start,
end,
},
)
.getOne()
if (alreadyRedeemed) {
logger.error(
'contribution link with rule DAILY already redeemed by user with id',
user.id,
)
throw new Error('Contribution link already redeemed today')
}
break
}
default: {
logger.error('contribution link has unknown cycle', contributionLink.cycle)
throw new Error('Contribution link has unknown cycle')
} }
break
} }
default: {
logger.error('contribution link has unknown cycle', contributionLink.cycle) const creations = await getUserCreation(user.id, clientTimezoneOffset)
throw new Error('Contribution link has unknown cycle') logger.info('open creations', creations)
validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset)
const contribution = new DbContribution()
contribution.userId = user.id
contribution.createdAt = now
contribution.contributionDate = now
contribution.memo = contributionLink.memo
contribution.amount = contributionLink.amount
contribution.contributionLinkId = contributionLink.id
contribution.contributionType = ContributionType.LINK
contribution.contributionStatus = ContributionStatus.CONFIRMED
await queryRunner.manager.insert(DbContribution, contribution)
const lastTransaction = await queryRunner.manager
.createQueryBuilder()
.select('transaction')
.from(DbTransaction, 'transaction')
.where('transaction.userId = :id', { id: user.id })
.orderBy('transaction.id', 'DESC')
.getOne()
let newBalance = new Decimal(0)
let decay: Decay | null = null
if (lastTransaction) {
decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now)
newBalance = decay.balance
} }
newBalance = newBalance.add(contributionLink.amount.toString())
const transaction = new DbTransaction()
transaction.typeId = TransactionTypeId.CREATION
transaction.memo = contribution.memo
transaction.userId = contribution.userId
transaction.previous = lastTransaction ? lastTransaction.id : null
transaction.amount = contribution.amount
transaction.creationDate = contribution.contributionDate
transaction.balance = newBalance
transaction.balanceDate = now
transaction.decay = decay ? decay.decay : new Decimal(0)
transaction.decayStart = decay ? decay.start : null
await queryRunner.manager.insert(DbTransaction, transaction)
contribution.confirmedAt = now
contribution.transactionId = transaction.id
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
await queryRunner.commitTransaction()
logger.info('creation from contribution link commited successfuly.')
} catch (e) {
await queryRunner.rollbackTransaction()
logger.error(`Creation from contribution link was not successful: ${e}`)
throw new Error(`Creation from contribution link was not successful. ${e}`)
} finally {
await queryRunner.release()
} }
const creations = await getUserCreation(user.id, clientTimezoneOffset)
logger.info('open creations', creations)
validateContribution(creations, contributionLink.amount, now, clientTimezoneOffset)
const contribution = new DbContribution()
contribution.userId = user.id
contribution.createdAt = now
contribution.contributionDate = now
contribution.memo = contributionLink.memo
contribution.amount = contributionLink.amount
contribution.contributionLinkId = contributionLink.id
contribution.contributionType = ContributionType.LINK
contribution.contributionStatus = ContributionStatus.CONFIRMED
await queryRunner.manager.insert(DbContribution, contribution)
const lastTransaction = await queryRunner.manager
.createQueryBuilder()
.select('transaction')
.from(DbTransaction, 'transaction')
.where('transaction.userId = :id', { id: user.id })
.orderBy('transaction.id', 'DESC')
.getOne()
let newBalance = new Decimal(0)
let decay: Decay | null = null
if (lastTransaction) {
decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now)
newBalance = decay.balance
}
newBalance = newBalance.add(contributionLink.amount.toString())
const transaction = new DbTransaction()
transaction.typeId = TransactionTypeId.CREATION
transaction.memo = contribution.memo
transaction.userId = contribution.userId
transaction.previous = lastTransaction ? lastTransaction.id : null
transaction.amount = contribution.amount
transaction.creationDate = contribution.contributionDate
transaction.balance = newBalance
transaction.balanceDate = now
transaction.decay = decay ? decay.decay : new Decimal(0)
transaction.decayStart = decay ? decay.start : null
await queryRunner.manager.insert(DbTransaction, transaction)
contribution.confirmedAt = now
contribution.transactionId = transaction.id
await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution)
await queryRunner.commitTransaction()
logger.info('creation from contribution link commited successfuly.')
} catch (e) {
await queryRunner.rollbackTransaction()
logger.error(`Creation from contribution link was not successful: ${e}`)
throw new Error(`Creation from contribution link was not successful. ${e}`)
} finally { } finally {
await queryRunner.release()
releaseLock() releaseLock()
} }
return true return true