race condition при получении бонуса
У меня есть игра в социальной сети, где я плачу бонус в монетах раз в 30 минут за просмотр рекламы.
Выглядит код так:
if($user_info['bonus_last_time'] + 1800 > $time) {
echo 'Бонус можно получать один раз в 30 минут.';
} else {
$db->query("
UPDATE `users`
SET `coins` = `coins` + 1000,
`bonus_last_time` = '$time'
WHERE
`id` = '".$user_info['id']."';
");
echo 'Бонус успешно получен.';
}
Проблема заключается в том, что если воспроизвести этот запрос одновременно несколько раз, то за раз можно получить бонус несколько раз и несмотря на условие, запросы всё равно проходят, то есть получается race condition.
Понимаю, что нужно использовать транзакции, чтобы избежать такого, но почему-то кажется не совсем правильным решением, а что если одновременно 1000 человек получат бонус, вдруг что-то пойдёт не так с транзакциями? И если честно, то хотелось бы другой способ, но я не знаю какой. Была идея создать отдельную таблицу и назвать её например users_bonus_queue с уникальным полем user_id и делать примерно что-то такое:
if($user_info['bonus_last_time'] + 1800 > $time) {
echo 'Бонус можно получать один раз в 30 минут.';
} else {
if($db->query("
INSERT INTO `users_bonus_queue` (`user_id`)
VALUES ('".$user_info['id']."')
")) {
$db->query("
UPDATE `users`
SET `coins` = `coins` + 1000,
`bonus_last_time` = '$time'
WHERE
`id` = '".$user_info['id']."';
");
echo 'Бонус успешно получен.';
} else {
echo 'Что-то пошло не так.';
}
}
Но тоже непонятно, в каком случае нужно потом удалить запись с пользователем в таблице users_bonus_queue, чтобы пользователь потом смог снова получить бонус.
Помогите, пожалуйста, как правильно сделать. Я несколько дней искал в поисковиках свою проблему, мучал chatGPT, но по итогу так и не понял если честно как мне быть. Надеюсь на помощь сообщества.