Прямой ответ
Длинный процесс — последовательность шагов, выполняемая минуты, часы или дни, с ожиданием внешних событий. Собственная реализация такого процесса требует сохранения состояния, повторов при сбоях и восстановления после перезапуска. 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. Проверяйте версии определений процесса. Изменение логики запущенного процесса требует совместимости с уже выполняющимися экземплярами.
Рекомендации:
- Не используйте движок для коротких задач. Последовательность из двух шагов без ожидания реализуется проще без внешней системы.
- Учитывайте стоимость инфраструктуры. Движок требует собственной кластерной системы и её сопровождения.
- Тестируйте процесс целиком. Тесты отдельных шагов не проверяют порядок и восстановление.
- Фиксируйте идентификатор экземпляра. Возможность найти процесс по бизнес-ключу необходима для разбора.
- Различайте сбой шага и сбой процесса. Повтор шага не равен перезапуску процесса с начала.
Практический сценарий: потерянные процессы после перезапуска исполнителя
Контекст: процесс согласования документа реализовывался собственным кодом с состоянием в таблице. После обновления сервиса часть процессов остановилась и не продолжилась.
- Диагностика. Состояние хранилось в таблице, но логика продолжения запускалась по расписанию и опрашивала только процессы в определённых статусах. Процессы, ожидавшие внешнего события, не попадали в опрос после изменения кода.
- Причина. Собственная реализация требовала самостоятельного управления восстановлением, таймерами и ожиданием событий. Изменение в опросе нарушило продолжение, а проверки этого сценария не было.
- Действия. (а) Процесс перевели на workflow engine с сохранением состояния и ожиданием сигнала; (б) шаги сделали идемпотентными, чтобы повтор после сбоя не выполнял действие дважды; (в) для каждого шага задали таймаут и политику повторов; (г) добавили метрику числа процессов в промежуточных состояниях с тревогой по таймауту; (д) потерянные процессы восстановили по журналу и добавили проверку согласованности.
- Результат. Перезапуск исполнителя больше не останавливает процессы, а ожидание подтверждения не требует опроса и не занимает ресурсов.
Вывод: собственный оркестратор длинных процессов требует самостоятельной реализации восстановления, таймеров и ожидания событий. Workflow engine берёт эти задачи на себя, но добавляет инфраструктуру и требует идемпотентности шагов.
FAQ
Когда нужен workflow engine? Когда процесс выполняется дольше одного запроса, ждёт внешних событий и требует восстановления после сбоя. Для коротких последовательностей он избыточен.
Чем движок отличается от очереди задач? Очередь выполняет отдельные задачи без состояния между ними. Движок ведёт процесс целиком, хранит состояние и управляет порядком шагов.
Как изменять логику запущенного процесса? С обеспечением совместимости с выполняющимися экземплярами либо завершением старых экземпляров и запуском новых по новому определению.
Что хранить в состоянии процесса? Идентификаторы и небольшие значения. Большие данные передаются по ссылке, чтобы не раздувать хранилище состояния.
Источники: Temporal docs (Workflows), Apache Airflow docs (DAGs), Azure Durable Functions — ссылки в шапке.