Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moscow Python Meetup №111. Как мы изобретали Te...

Moscow Python Meetup №111. Как мы изобретали Temporal, пытаясь просто создать приложение

Ларин Андрей. Старший разработчик, группа разработки IDP, Яндекс.

Видео: https://moscowpython.ru/meetup/111/inventing-temporal/

Moscow Python: http://moscowpython.ru
Курсы Learn Python: http://learn.python.ru
Moscow Python Podcast: http://podcast.python.ru
Заявки на доклады: https://bit.ly/mp-speaker

Avatar for Moscow Python Meetup

Moscow Python Meetup PRO

May 19, 2026

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. Кто я? Старший разработчик, Группа разработки IDP, Яндекс ▪ 8+

    лет в Python ▪ 3+ года в Яндекс Ларин Андрей 2
  2. Введение Бизнес задача создание приложения по кнопке 01 1 1.

    Создать приложение в БД 2. Завести задачу в трекере 6
  3. Введение Бизнес задача создание приложения по кнопке 01 1 1.

    Создать приложение в БД 2. Завести задачу в трекере 3. Дождаться аппрува от СИБ 7
  4. Введение Бизнес задача создание приложения по кнопке 01 1 1.

    Создать приложение в БД 2. Завести задачу в трекере 3. Дождаться аппрува от СИБ 4. Запустить и дождаться CI 8
  5. Введение Бизнес задача создание приложения по кнопке 01 1 1.

    Создать приложение в БД 2. Завести задачу в трекере 3. Дождаться аппрува от СИБ 4. Запустить и дождаться CI 5. Развернуть инфру 9
  6. Идеальный мир (Синхронный код) В мире, где сеть не моргает,

    а серверы не падают, код выглядит как спецификация. 11
  7. Серверы падают Воркер Celery может упасть (OOM, деплой) в самый

    неподходящий момент. Как это решают обычно: 1. Reconciler (Cron-джоба) 2. Transactional Outbox 13
  8. Гонки Пример: Ручной рестарт 1. CI упал пока step4_poll_ci ждал

    в очереди. Пользователь жмет "Перезапустить CI". 2. Django запускает новый пайплайн: launch #2. 3. В брокере всё еще висит отложенная задача step4_poll_ci от первого запуска. 4. Старая задача просыпается, видит, что старый launch #1 упал, и пишет в БД: state = FAILED. 5. Итог: Новый launch #2 успешно работает, но приложение в БД уже помечено как упавшее.
  9. Гонки Пример: Ручной рестарт 1. CI упал пока step4_poll_ci ждал

    в очереди. Пользователь жмет "Перезапустить CI". 2. Django запускает новый пайплайн: launch #2. 3. В брокере всё еще висит отложенная задача step4_poll_ci от первого запуска. 4. Старая задача просыпается, видит, что старый launch #1 упал, и пишет в БД: state = FAILED. 5. Итог: Новый launch #2 успешно работает, но приложение в БД уже помечено как упавшее.
  10. Гонки Пример: Ручной рестарт 1. CI упал пока step4_poll_ci ждал

    в очереди. Пользователь жмет "Перезапустить CI". 2. Django запускает новый пайплайн: launch #2. 3. В брокере всё еще висит отложенная задача step4_poll_ci от первого запуска. 4. Старая задача просыпается, видит, что старый launch #1 упал, и пишет в БД: state = FAILED. 5. Итог: Новый launch #2 успешно работает, но приложение в БД уже помечено как упавшее.
  11. Осознание Мы хотели просто создать приложение, а написали свой собственный

    Workflow Engine: 1.Стейт-машина в БД 2.Поллинг на отложенных задачах 3.Reconciler / Outbox для зависших процессов 4.Система поколений от гонок 03 18
  12. Осознание Мы хотели просто создать приложение, а написали свой собственный

    Workflow Engine: 1.Стейт-машина в БД 2.Поллинг на отложенных задачах 3.Reconciler / Outbox для зависших процессов 4.Система поколений от гонок 03 И это для 5 шагов! В реальности в нашем проекте их ~20. Это 20 "Опасных зон". 19
  13. Что такое Temporal? Temporal - это клей для распределенных систем,

    который гарантирует, что ваша бизнес-логика выполнится до конца 04 21
  14. Спасение (Код на Temporal) Workflow: Здесь описывается общая бизнес-логика процесса

    в виде кода. Обязан быть детерминированным. Activity: Содержит непосредственную бизнес-логику и выполняет конкретную задачу. Может быть недетерминированным. 25
  15. Спасение (Код на Temporal) Workflow: Здесь описывается общая бизнес-логика процесса

    в виде кода. Обязан быть детерминированным. Activity: Содержит непосредственную бизнес-логику и выполняет конкретную задачу. Может быть недетерминированным. 26
  16. Спасение (Код на Temporal) Ожидание выполнения определенного условия внутри Workflow.

    Не блокирует CPU Обработчик обновлений Workflow. В данном случае переключает флаг для wait_condition 28
  17. Спасение (Код на Temporal) Восстановление состояния. Если Workflow внезапно упал

    (например, из-за нехватки памяти или перезагрузки сервера), Temporal не теряет прогресс. 29
  18. Спасение (Код на Temporal) Можем перезапустить Workflow из любой части

    истории выполнения Повисли в ожидании 30
  19. Детерминизм и недетерминизм 05 Недетермензм гарантированно приводит к поломке и

    остановке бизнес-процесса и его очень сложно потом чинить. 33
  20. Строго запрещено внутри Workflow: datetime.now() random.random() uuid.uuid4() Сетевые запросы или

    походы в БД напрямую Решение: Использовать детерминированные аналоги из SDK Temporal. 35
  21. Проблема изменения кода Что если у нас 1000 запущенных процессов,

    а мы выкатили новый код, добавив шаг в середину? 36
  22. Проблема изменения кода Что если у нас 1000 запущенных процессов,

    а мы выкатили новый код, добавив шаг в середину? При Replay старые процессы попытаются пройти по новому коду. История скажет: "следующий шаг B", а код скажет: "нет, теперь тут шаг C". 37
  23. Проблема изменения кода Что если у нас 1000 запущенных процессов,

    а мы выкатили новый код, добавив шаг в середину? При Replay старые процессы попытаются пройти по новому коду. История скажет: "следующий шаг B", а код скажет: "нет, теперь тут шаг C". Решение 1: Использовать Inline Patching 38
  24. Проблема изменения кода Что если у нас 1000 запущенных процессов,

    а мы выкатили новый код, добавив шаг в середину? При Replay старые процессы попытаются пройти по новому коду. История скажет: "следующий шаг B", а код скажет: "нет, теперь тут шаг C". Решение 2: Версионирование (Создание V2) 39
  25. Проблема изменения кода Что если у нас 1000 запущенных процессов,

    а мы выкатили новый код, добавив шаг в середину? При Replay старые процессы попытаются пройти по новому коду. История скажет: "следующий шаг B", а код скажет: "нет, теперь тут шаг C". Решение 2: Версионирование (Создание V2) 1. Вы создаете CreateApplicationWorkflowV2. 2. Воркер слушает и V1, и V2. 3. Новые запросы идут в V2. Старые дорабатывают по V1. 40
  26. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 43
  27. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State GRPC Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 44
  28. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State GRPC GRPC GRPC Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 45
  29. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State GRPC GRPC GRPC На старте Workflow история событий Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 46
  30. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State На старте Workflow история событий GRPC GRPC GRPC Запланируй activity Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 47
  31. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State На старте Workflow история событий GRPC GRPC GRPC Запланируй activity Выполни activity Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 48
  32. Temporal Server ├ Task Queues ├ Event History ├ Timers

    / State На старте Workflow история событий GRPC GRPC GRPC Запланируй activity Выполни activity Результат Activity Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless Worker Process ├ Workflow Code ├ Activity Code ├ SDK ├ Stateless 49
  33. Temporal Python SDK запускает код Workflow в строгой песочнице (sandbox),

    чтобы защитить вас от случайного недетерминизма. Песочница перехватывает импорты и блокирует доступ к сети, файловой системе и потокам. 51
  34. Temporal Python SDK запускает код Workflow в строгой песочнице (sandbox),

    чтобы защитить вас от случайного недетерминизма. Песочница перехватывает импорты и блокирует доступ к сети, файловой системе и потокам. Решение: Прокинуть модуль в песочницу можно через imports_passed_through 52
  35. Сборка и запуск Воркера Определяем как будут запускаться синхронные activities,

    через потоки или процессы Определяем какие Workflows и Activities будут работать в воркере 57
  36. Сборка и запуск Воркера Определяем как будут запускаться синхронные activities,

    через потоки или процессы Определяем какие Workflows и Activities будут работать в воркере Декоратор async_to_sync для запуска воркера в синхронном коде 58
  37. Выводы 08 Когда брать Temporal Сложные бизнес-процессы (много шагов) Long-running

    flows (ожидание днями) Нужна надежность при падениях 60
  38. Выводы 08 Когда НЕ брать Простые фоновые задачи (Celery) Cron

    без состояния (Celery Beat) Коротко живущие процессы 61