Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Workflow engine для длинных процессов

Workflow engine: выполнение длинных процессов с восстановлением после сбоя

Workflow engine: сохраняемое состояние процесса, отличие от планировщика задач, повторы шагов, таймеры, компенсация и когда собственный оркестратор избыточен.

Прямой ответ

Длинный процесс — последовательность шагов, выполняемая минуты, часы или дни, с ожиданием внешних событий. Собственная реализация такого процесса требует сохранения состояния, повторов при сбоях и восстановления после перезапуска. Workflow engine берёт эти задачи на себя.

Ключевое свойство — сохраняемое выполнение. Состояние процесса хранится во внешней системе, поэтому перезапуск исполнителя продолжает процесс с места остановки, а не начинает заново.

Отличие от планировщика задач:

Планировщик задач Workflow engine
Единица работы Отдельная задача Последовательность шагов
Состояние между шагами Не хранится Хранится
Ожидание внешнего события Не поддерживается Поддерживается
Повтор после сбоя Задача целиком С текущего шага
Компенсация шагов В коде задачи Механизм движка

Планировщик запускает задачу и забывает о ней. Workflow engine ведёт процесс: знает, какой шаг выполнен, ждёт внешнего сигнала и продолжает после получения; о фоновых задачах — в статье про Celery.

Типичный процесс описывается последовательностью шагов:

@workflow.defn
class OrderProcess:
    @workflow.run
    async def run(self, order_id: int) -> None:
        await workflow.execute_activity(charge_payment, order_id,
                                        start_to_close_timeout=timedelta(minutes=5))
        await workflow.execute_activity(reserve_stock, order_id,
                                        start_to_close_timeout=timedelta(minutes=5))
        await workflow.wait_condition(lambda: self.shipping_confirmed)
        await workflow.execute_activity(notify_customer, order_id,
                                        start_to_close_timeout=timedelta(minutes=1))

Каждый шаг выполняется с таймаутом и повтором при сбое. Ожидание подтверждения может длиться дни, и процесс не занимает ресурсов во время ожидания.

Три задачи, которые решает движок:

1. Повтор шага при сбое. Шаг повторяется с нарастающей задержкой, а логика повтора не пишется в коде процесса.

2. Восстановление после перезапуска. Исполнитель может быть остановлен и запущен снова, процесс продолжится с сохранённого шага.

3. Таймеры и ожидание. Отсрочка на сутки не удерживает поток выполнения, а реализуется механизмом движка.

Компенсация при отказе шага описывается отдельно: движок знает, какие шаги выполнены, и может вызвать обратные действия; о механизме — в статье про компенсацию.

Практика: применение workflow engine

1. Применяйте движок для процессов с ожиданием. Процесс, ждущий подтверждения часами, в собственном решении требует хранения состояния и опроса.

2. Делайте шаги идемпотентными. Повтор шага после сбоя возможен, и действие не должно выполняться дважды; о саге — в статье про сагу и outbox.

3. Задавайте таймауты для каждого шага. Шаг без таймаута может остановить процесс навсегда.

4. Разделяйте логику процесса и шаги. Процесс описывает порядок, шаг выполняет действие. Смешение затрудняет повтор отдельного шага.

5. Храните в состоянии процесса только необходимое. Большие данные передаются по ссылке, а не хранятся в состоянии; о размере — в статье про размер сообщения.

6. Описывайте компенсацию для обратимых шагов. Не все действия отменяемы, и для них требуется другой подход.

7. Мониторьте остановившиеся процессы. Процесс в промежуточном состоянии дольше ожидаемого — признак сбоя; о метриках — в статье про оркестрацию.

8. Проверяйте версии определений процесса. Изменение логики запущенного процесса требует совместимости с уже выполняющимися экземплярами.

Рекомендации:

  1. Не используйте движок для коротких задач. Последовательность из двух шагов без ожидания реализуется проще без внешней системы.
  2. Учитывайте стоимость инфраструктуры. Движок требует собственной кластерной системы и её сопровождения.
  3. Тестируйте процесс целиком. Тесты отдельных шагов не проверяют порядок и восстановление.
  4. Фиксируйте идентификатор экземпляра. Возможность найти процесс по бизнес-ключу необходима для разбора.
  5. Различайте сбой шага и сбой процесса. Повтор шага не равен перезапуску процесса с начала.

Практический сценарий: потерянные процессы после перезапуска исполнителя

Контекст: процесс согласования документа реализовывался собственным кодом с состоянием в таблице. После обновления сервиса часть процессов остановилась и не продолжилась.

  1. Диагностика. Состояние хранилось в таблице, но логика продолжения запускалась по расписанию и опрашивала только процессы в определённых статусах. Процессы, ожидавшие внешнего события, не попадали в опрос после изменения кода.
  2. Причина. Собственная реализация требовала самостоятельного управления восстановлением, таймерами и ожиданием событий. Изменение в опросе нарушило продолжение, а проверки этого сценария не было.
  3. Действия. (а) Процесс перевели на workflow engine с сохранением состояния и ожиданием сигнала; (б) шаги сделали идемпотентными, чтобы повтор после сбоя не выполнял действие дважды; (в) для каждого шага задали таймаут и политику повторов; (г) добавили метрику числа процессов в промежуточных состояниях с тревогой по таймауту; (д) потерянные процессы восстановили по журналу и добавили проверку согласованности.
  4. Результат. Перезапуск исполнителя больше не останавливает процессы, а ожидание подтверждения не требует опроса и не занимает ресурсов.

Вывод: собственный оркестратор длинных процессов требует самостоятельной реализации восстановления, таймеров и ожидания событий. Workflow engine берёт эти задачи на себя, но добавляет инфраструктуру и требует идемпотентности шагов.

FAQ

Когда нужен workflow engine? Когда процесс выполняется дольше одного запроса, ждёт внешних событий и требует восстановления после сбоя. Для коротких последовательностей он избыточен.

Чем движок отличается от очереди задач? Очередь выполняет отдельные задачи без состояния между ними. Движок ведёт процесс целиком, хранит состояние и управляет порядком шагов.

Как изменять логику запущенного процесса? С обеспечением совместимости с выполняющимися экземплярами либо завершением старых экземпляров и запуском новых по новому определению.

Что хранить в состоянии процесса? Идентификаторы и небольшие значения. Большие данные передаются по ссылке, чтобы не раздувать хранилище состояния.

Источники: Temporal docs (Workflows), Apache Airflow docs (DAGs), Azure Durable Functions — ссылки в шапке.