Просто некоторые дальнейшие улучшения в существующем ответе.
Leaderboard.update()
и AssignedJob.update()
- это асинхронные c функции, которые следует ожидать, поэтому функцию обратного вызова необходимо преобразовать в async
функция. Это гарантирует, что обещание не будет выполнено до тех пор, пока не будут выполнены все операции с базой данных, а не только findOrCreate()
:
const promises = todayAssignedJobs.map(async todayAssigned => {
const [leaderboard, created] = await Leaderboard.findOrCreate({...});
if (!created) {
const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
const commission = todayAssigned.commission + leaderboard.commission;
const jobsCompleted = leaderboard.jobs_completed + 1;
await Leaderboard.update({
rating,
commission,
jobs_completed: jobsCompleted,
updated_by: 'system',
}, {
where: {
id: leaderboard.id,
},
});
}
await AssignedJob.update({
is_leaderboard_generated: true,
}, {
where: {
id: todayAssigned.id,
},
});
});
await Promise.all(promises);
. Более фундаментальная проблема с этим подходом состоит в том, что Leaderboard.findOrCreate()
и Leaderboard.update()
не является частью одной транзакции. Это проблематично c, поскольку update()
зависит от текущего значения записи в leaderboard
, что создает состояние гонки в вашей базе данных из-за модификации non-atomi c запись:
const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
const commission = todayAssigned.commission + leaderboard.commission;
const jobsCompleted = leaderboard.jobs_completed + 1;
Каждый из методов должен быть помечен как часть одной транзакции. С помощью sequelize. js вы можете достичь этого, используя управляемую транзакцию :
const promises = todayAssignedJobs.map(
todayAssigned => sequelize.transaction(async transaction => {
const [leaderboard, created] = await Leaderboard.findOrCreate({
transaction,
...
});
if (!created) {
const rating = (todayAssigned.rating + leaderboard.rating * leaderboard.jobs_completed) / (leaderboard.jobs_completed + 1);
const commission = todayAssigned.commission + leaderboard.commission;
const jobsCompleted = leaderboard.jobs_completed + 1;
await Leaderboard.update({
rating,
commission,
jobs_completed: jobsCompleted,
updated_by: 'system',
}, {
transaction,
where: {
id: leaderboard.id,
},
});
}
await AssignedJob.update({
is_leaderboard_generated: true,
}, {
transaction,
where: {
id: todayAssigned.id,
},
})
})
);
await Promise.all(promises);