Приветствую всех. Столкнулся с задачей: есть контроллер, который принимает ajax запрос и передаёт данные из запроса в job, а затем job уже записывает эти данные в MySQL DB. В контроллере: PHP: $this->dispatch(new WriteMessageToDB($userId, $roomId, $body, $arrived_at)); Job: PHP: class WriteMessageToDB implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; protected $userId; protected $roomId; protected $body; protected $arrived_at; /** * WriteMessageToDB constructor. * @param $userId * @param $roomId * @param $body * @param $arrived_at */ public function __construct($userId, $roomId, $body, $arrived_at) { $this->userId = $userId; $this->roomId = $roomId; $this->body = $body; $this->arrived_at = $arrived_at; } /** * Execute the job. * * @return mixed */ public function handle() { //persisting to DB $cue = Message::create([ 'user_id' => $this->userId, 'room_id' => $this->roomId, 'body' => $this->body, 'arrived_at' => $this->arrived_at, ]); return $cue; } В консоли запускаю: Код (Text): php artisan queue:work database --tries=1 Проблема в том, что сообщения в базу данных не всегда записываются в том порядке, в каком пришли: иногда те, что пришли раньше записываются в базу позже. От front-end'а запросы идут в правильном порядке, ошибок при выполнении job'ов тоже нет. Я думал очередь поправит это дело, но похоже, я что-то упускаю из-виду. Буду рад любой помощи. Спасибо.
Очереди для того, чтобы одну запись в БД сделать - это слишком. Про порядок - сортируйте по arrived_at и вам по барабану должно быть
Почему слишком, разве это не поможет приложению быстрее работать? Неправильный порядок при уже отсортированных по arrived_at записях: более поздние сообщения оказываются записанными на несколько сот миллисекунд раньше, чем более ранние.
Не поможет, тем более у тебя очереди через базу, т.е. ты вместо одной операции вставки делаешь две (в таблицу очередей, а потом в таблицу с сообщениями) Ну тут уже, если это супер-пупер критично, надо какие-нибудь изобретать Mutex-ы, ведь скрипт сайта запускается параллельно в нескольких экземплярах. Я даже не сильно себе такой mutex представляю, честно говоря
Хотелось бы заметить, что в SQL, как в стандарте, порядок гарантируется только при задании инструкции сортировки в запросе. Потому полагаться на порядок добавления записей - нельзя. Более того, если вы станете перебирать большую таблицу через LIMIT OFFSET без ORDER BY, то теоретически, рискуете нарваться на дубликаты. Другое дело, что MySQL, используемый в большинстве случаев, как правило отдает строки именно в порядке добавления и потому эту деталь многие пропускают, пока не столкнутся с другим движком. --- Добавлено --- Это поможет быстрее отдать фронту ответ, но у фронта нет гарантии, что данные действительно были записаны, очередь отработалось и не выстрелил при этом один из эксепшенов. Т.к. добавление / изменение данных по запросу с фронта обычно дешевая операция (вставил запись / отредактировал / изменил), то время работы с БД будет незначительным по сравнению с бутстрапом фреймворка и сетевой частью - экономить тут нечего и очереди смысла не имеют. Потому что если перестает держать БД или фронт - нужно балансировать именно их, вместо внедрения новой сущности, которая забирает на себя ресурсы выполняя лишнее действие. С другой стороны, если при выполнении экшена делается ещё что-то: расчеты, обращение к другим api, обработка данных, короче что-то, что увеличивает время выполнения запроса до неприлично долгого для данного кейса, вот тогда и надо переносить действие в очередь, предоставив при этом фронту возможность получить результат выполнения тем или иным способом. В теории, как-то так )
Вот на что хочется ещё обратить внимание. Для обработки множества входящих запросов сервер использует несколько параллельных процессов с PHP, и после того, как эти параллельные процессы запущены, нам уже не проконтролировать, как ОС распределить между ними процессорное время. И если у тебя запросы приходят с разницей в миллисекунды, то вполне может такое быть, что запущенный позже процесс доберётся до записи в базу раньше, чем запущенный на миллисекунду раньше. Поэтому тут нужны мютексы - т.е. такие флаги, к которым имеют доступ оба процесса, и которые могут сказать: подожди, я ещё не записал в базу, потом ты запишешь. Можно реализовать через какой-нибудь Redis, а можно и просто с помощью средств MySQL (см GET_LOCK). Но с этим тоже не всё так просто, потому что могут быть так называемые дэдлоки, короче, это вообще отдельная песня. А что у тебя за чат такой, в который люди пишут с разницей в миллисекунды, и это важно? Ведь даже если нагрузка очень большая, в конкретный один чат люди никак не могут писать с такой скоростью