Slide 1

Slide 1 text

Как мы изобретали Temporal Старший разработчик Ларин Андрей пытаясь просто создать приложение

Slide 2

Slide 2 text

Кто я? Старший разработчик, Группа разработки IDP, Яндекс ▪ 8+ лет в Python ▪ 3+ года в Яндекс Ларин Андрей 2

Slide 3

Slide 3 text

Введение 01 1 3

Slide 4

Slide 4 text

Введение Бизнес задача создание приложения по кнопке 01 1 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

02 Наивный подход на Django + Celery 10

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Распределенная реальность (Celery) Берем Celery. Разрываем красивый код на куски (стейт-машину) и связываем через БД. 12

Slide 13

Slide 13 text

Серверы падают Воркер Celery может упасть (OOM, деплой) в самый неподходящий момент. Как это решают обычно: 1. Reconciler (Cron-джоба) 2. Transactional Outbox 13

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

Решение проблемы гонки – ввести поколения 17

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

Что такое Temporal? Описание раздела в одну или две строки 04 20

Slide 21

Slide 21 text

Что такое Temporal? Temporal - это клей для распределенных систем, который гарантирует, что ваша бизнес-логика выполнится до конца 04 21

Slide 22

Slide 22 text

Спасение (Код на Temporal) 22

Slide 23

Slide 23 text

Спасение (Код на Temporal) 23

Slide 24

Slide 24 text

Спасение (Код на Temporal) Workflow: Здесь описывается общая бизнес-логика процесса в виде кода. Обязан быть детерминированным. 24

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Спасение (Код на Temporal) Ожидание выполнения определенного условия внутри Workflow. Не блокирует CPU 27

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Спасение (Код на Temporal) Восстановление состояния. Если Workflow внезапно упал (например, из-за нехватки памяти или перезагрузки сервера), Temporal не теряет прогресс. 29

Slide 30

Slide 30 text

Спасение (Код на Temporal) Можем перезапустить Workflow из любой части истории выполнения Повисли в ожидании 30

Slide 31

Slide 31 text

Детерминизм и недетерминизм 05 31

Slide 32

Slide 32 text

Детерминизм и недетерминизм 05 Workflow обязан выдавать один и тот же результат при каждом запуске (Replay). 32

Slide 33

Slide 33 text

Детерминизм и недетерминизм 05 Недетермензм гарантированно приводит к поломке и остановке бизнес-процесса и его очень сложно потом чинить. 33

Slide 34

Slide 34 text

Строго запрещено внутри Workflow: datetime.now() random.random() uuid.uuid4() Сетевые запросы или походы в БД напрямую 34

Slide 35

Slide 35 text

Строго запрещено внутри Workflow: datetime.now() random.random() uuid.uuid4() Сетевые запросы или походы в БД напрямую Решение: Использовать детерминированные аналоги из SDK Temporal. 35

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Архитектура Temporal 06 41

Slide 42

Slide 42 text

Temporal Server ├ Task Queues ├ Event History ├ Timers / State 42

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Python SDK Temporal 07 50

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

Temporal Python SDK построен вокруг asyncio Но позволяет запускать синхронный код внутри Activities. 53

Slide 54

Slide 54 text

Temporal Python SDK построен вокруг asyncio Но позволяет запускать синхронный код внутри Activities. 54

Slide 55

Slide 55 text

Сборка и запуск Воркера 55

Slide 56

Slide 56 text

Сборка и запуск Воркера Определяем какие Workflows и Activities будут работать в воркере 56

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

Выводы 08 59

Slide 60

Slide 60 text

Выводы 08 Когда брать Temporal Сложные бизнес-процессы (много шагов) Long-running flows (ожидание днями) Нужна надежность при падениях 60

Slide 61

Slide 61 text

Выводы 08 Когда НЕ брать Простые фоновые задачи (Celery) Cron без состояния (Celery Beat) Коротко живущие процессы 61

Slide 62

Slide 62 text

Вопросы? Ларин Андрей Старший разработчик 62