Когда два или более HTTP-запроса выполняются одновременно (например, с curl_multi_exec) к заданной конечной точке с использованием одного и того же идентификатора сеанса. Объекты Symfony / Doctrine загружаются с «текущими» данными базы данных.
Представьте себе следующий сценарий:
- пользовательских хитов / трансфер / usd? Сумма = 10
- внутри контроллера есть:
$withdrawAmount = $request->get('amount');
if($currentUser->getBalance() >= $withdrawAmount)
{
//sure - you can transfer your money somewhere...
$currentUser->setBalance($currentUser->getBalance() - withdrawAmount);
$em->persist($currentUser);
$em->flush();
//send money somewhere
...
//do something time consuming, etc
...
}
Теперь в контексте параллельного запроса два или более запроса, попадающих в одну и ту же конечную точку, фактически будут проходить проверку getBalance (), поскольку она будет считывать «текущий» баланс, что приводит к нескольким передачам, когда это вообще не должно быть возможным. Запись в базе данных будет обновляться несколько раз, но последний запрос будет содержать последнее слово, и если его сумма равна 0,01, это все, что будет выведено из текущего баланса пользователя.
Использование очереди с cronjob решит вышеупомянутую проблему, но все же элементы очереди будут вставлены по той же причине - проверка «провал» в контроллере.
Это всего лишь воображаемый сценарий, но действительный - это происходит по-настоящему.
Как можно преодолеть это? (Я даже не уверен, как назвать эту «проблему»)