Вам нужны
мьютексы. Можно реализовать разными способами. Но если у вас планируется распределенное приложение, то можно сделать на основе mysql, используя
GET_LOCK() и
RELEASE_LOCK().
К сожалению, не нашел готового для laravel фреймворка, но можно сделать самому подсмотрев как сделано у
других.
Задача добиться выполнения приложения в один поток. Мьютекс можно захватывать перед началом работы экшена и отпускать после выполнения.
mysql> SELECT GET_LOCK('name', 10); //первая сессия.
mysql> SELECT GET_LOCK('name', 5) //вторая сессия. будет висеть, пока не истечет таймаут в 10 секунд или пока первая сессия не выпустит SELECT RELEASE_LOCK('name');
Блокировки можно именовать как "controllerName:ActionName". Это значит, что если первый поток взял GET_LOCK("controllerName:ActionName", 10); то второй поток к тому же самому экшену подвиснет и подождет, пока первый поток снимет блокировку. Таким образом, мы добиваемся того, что все запросы к серверу будут выполняться синхронно.
Также, можно воспроизвести
состояние гонки и посмотреть, что будет происходить с приложением, без мьютексов и с ними. Этого можно добиться используя curl в терминале:
curl -d 'param1=value1¶m2=value2' http://mylaravel.app/addBookInfo & curl -d 'param1=value1¶m2=value2' http://mylaravel.app/addBookInfo & wait
В итоге к приложению будет отправлено два одновременных запроса.
Также стоит упомянуть нативные сессии, если речь касается PHP. Так как они реализованы с помощью файлов, то один из запросов подвиснет, так как не сможет получить доступ на запись в файл сессии, пока с ним работает другой поток. Это может создать у разработчика ложное впечатление о том, что его код синхронный и соответственно не подвержен состоянию гонки, но это не так. Здесь нужно детальнее изучать код, в каких точках файл сессии блокируется, а в каких точках программы блокировка файла отпускается.