@AlekseyKuzmin
SPB

Реальзация очереди долгих заданий в MySQL + PHP

Есть некая очередь задач (>1M). Предполагается хранить очередь заданий в таблице MySQL.

Новые задачи помечаются флагом NEW.
Каждая задачи из очереди выполняются неким скриптом обработчиком около 3 минут.
После выполнения задача помечается в очереди флагом READY.
В случае ошибки или аварийного завершения скрипта — выполнение задачи нужно повторить.

Скриптов нужно запускать несколько в параллель.

Вопрос1: Как показать другим инстансам скрипта (которые запускаются параллельно) что задача находится в процессе выполнения, таким образом чтобы в случае аварийного завершения запись в базе откатывалась к изначальному состоянию т.е. NEW?

У меня вот такое решение
a) запуск скрипта обработчика -> помечаем задачу как PROCESSING + пишем время
потом
-> если все хорошо то задача становится READY
-> если авария то задача так и остается PROCESSING

б) Создаем еще один скрипт который проверяет задачи на наличие статуса PROCESSING более 10 минут и обнуляет его на NEW.

Так повисшие задачи будут запущены повторно + можно фиксировать кол-во попыток.

Вопрос2: Есть ли более элегантное решение?
  • Вопрос задан
  • 5865 просмотров
Пригласить эксперта
Ответы на вопрос 7
iSage
@iSage
Почему бы не использовать для очереди MQ, например тот же RabbitMQ. Оно и шустрое, и умеет несколько паралельных воркеров
Ответ написан
Комментировать
@cat_crash
Да, вам надо использовать многопоточность. Нативной поддержки многопоточности у PHP нет, но есть «костыль», описанный вот тут phplens.com/phpeverywhere/?q=node/view/254
Ответ написан
Комментировать
Halfi
@Halfi
Пункт б — жутки костыль. Вы можете обернуть выполнение запроса в транзакцию и исключение. Уже в исключении меняете статус на какой-нибудь фатал и дальше можете повесить демон, ищущий фаталы и обрабатывающий их. Если обработка не требуется, можете просто менять статус на нью и делать плюс один к счетчику фаталов.
Ответ написан
Комментировать
@Nikius
Веб-программист
Если запускать задачи кроном, то многопоточность будет организована автоматически.

По самому вопросу: Возможно стоит переработать сам скрипт, чтобы он мог корректно обработать хотя бы часть ошибок (а если возможно, то все) и мог установить статус NEW самостоятельно. А ваше решение использовать как запасной план :)
Ответ написан
Комментировать
Очередь заданий хорошо реализуется с помощь Pub/Sub в Redis
Ответ написан
Комментировать
Мы в похожей ситуации используем на проекте gearman.
Ответ написан
Комментировать
karellen
@karellen
Редис вообще хорошо для этого подходит. Для легковесных вариантов мне лично больше нравится BLPOP + RPUSH — блокирующий pop слева, пополнение задач справа. Ну или наоборот. В чистом виде FIFO-очередь, плюс воркеры могут легко вернуть задачу обратно через тот же RPUSH в случае временной ошибки. BLPOP отдает и ключ, из которого удалось pop-нуть, и само значение. Так удобно дифференцировать сами задачи.

Вопрос 1 — При blpop-е ставить ключ с идентификатором задачи куда-то. В хэш или просто в кейспейс. Откат — через транзакции, естественно, оборачивая все тело воркера в абсолютный отлов исключений.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы