@i-c-stars

Архитектура сервиса обработки задач [PHP]?

Приветствую!

Есть тривиальная задача - отправлять письма, смс, вызывать какие-то эндпоинты и прочее, по тригеру

Текущая реализация -
Прилетает, скажем, запрос на создание заказа от пользователя, в сопутствующий эндпоинт
Происходит всякая подкапотная работа скрипта и добавляется в таблицу задач, задача на отправку письма "Спасибо за заказ бла-бла-бла"
В фоне, в бесконечном цикле, работает php скрипт, который обрабатывает задачи из таблицы

Проблема - не хвататет скорости поточной обработки, а асинхронности в PHP нет

Опыта в работе с брокерами очередей у меня нет, но на сколько понимаю, сами они не вызывают эндпоинты, а ждут пока кто-нибудь заберет эту самую задачу, т.е. никакого профита от внедрения не будет

Есть библиотеки для работы с потоками. На данный момент остановился именно на такой реализации, брать пачку задач и для каждой запускать свой поток, дожидаться выполнения всех, изменять статусы задач и брать новую пачку

Но что-то мне подсказывает, что данную задачу можно решить куда проще и наверняка она уже давно решена. Нагуглить чего-то подходящего не удалось
  • Вопрос задан
  • 203 просмотра
Пригласить эксперта
Ответы на вопрос 1
@rPman
асинхронности в PHP нет
Если основная причина того что обработчик событий не успевает - в том что он долго:
* отправляет сетевой запрос (отправка sms или почта)
* просто таймеры, например запросы сетевые отправлять нужно с интервалами
* работа с файлами (асинхронно будет быстрее)
то на это вполне существуют асинхронные фреймворки, например очень мощный ReactPHP, у него очень хорошая база, большое коммунти и мне кажется на любой чих найдется библиотека.

Если же речь о чем то абстрактном
(например запускается внешний процесс и нужно ждать его ответ) то тут асинхронность вполне реализуется самостоятельно. да конечно есть готовые библиотеки (в зависимости от того можно ли держать очередь в памяти или в базе данных, тот же брокер событий reactPHP вполне можно взять за основу).

Основная идея в том что каждая твоя операция должна иметь несколько состояний (условно их можно реализовывать как одним параметром так и несколькими)
- Ожидает исполнения
- Запущено и ожидает окончания
- Окончено без ошибок
- Окончено с ошибкой и требует повтора
- Окончено с фатальной ошибкой.
Дальше я предполагаю что событие и действие это одно и то же (иначе нужно заводить отдельно очередь действий, например если одно событие это несколько действий друг за другом или одновременно, но обрабатывать их так же можно одним брокером).

Скрипт обработки событий смотрит на текущие события и при необходимости тупо запускает фоновый процесс на каждое действие (можно считать количество процессов со статусом "Запущено и ожидает окончание" и если их больше лимита - ничего не делать, пропускать, т.е. ждать изменений в очереди или просто сбыдлокодить sleep).

Так же этот скрипт может следить за временем исполнения задач (например повторы), достаточно просто сохранить время последней попытки и где то определить, какие задачи какие временные лимиты (я это определял в коде php, никто не мешает это прямо в базе данных у задачи определять)

Задача фонового процесса отметиться в базе данных, правкой состояния
- Ожидает исполнения -> Запущено и ожидает окончания
- Запущено и ожидает окончания -> Окончено ...

Скрипт может сам следить за pid процессов, отмечая у себя какой процесс был запущен для какой задачи, таким образом можно отлавливать вмешательство администратора или ОС (например из-за нехватки памяти) и как то интерпретировать это (повторить попытку или отвести в статус фатальных).

В итоге, любая задача будет запущена в виде процесса ОС, в linux это делается с помощью bash ... & а в windows - например start /min. Сам процесс обработки очередей будет занят сном, чтением списка процессов и проверкой pid уже запущенных, на это не требуется никаких особых ресурсов (при необходимости очередью может рулить этот процесс, буквально вместо базы данных слушать сокеты и принимать заявки на исполнение, в phpreact для этого все готово, даже слабые машины могут легко тянуть десятки тысяч запросов, я эксприментировал с websocket)

p.s. самый тупой демон параллелизации запуска процессов - это командная утилита linux parallel, ей можно отдавать список команд через linux pipe, построчно, он будет ждать новую команду если всю работу выполнил и тормозить основной процесс, если буфер пайпа переполнен (он настраивается). Само собой следить за тем как все исполняется придется самому.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽