Вычислительные единицы
Wippy предоставляет три способа выполнения кода: функции, процессы и workflows. Они используют одну и ту же базовую механику, но различаются временем жизни, местом хранения состояния и поведением при сбоях.
Функции
Функции — простейшая модель. Вызываете их, они выполняются, возвращают результат. Состояние между вызовами не сохраняется.
local result = funcs.call("app.math:add", 2, 3)
Функции выполняются в контексте вызывающего. Если вызывающий отменяется или завершается, запущенные функции тоже отменяются. Это упрощает жизнь — не нужно думать об очистке.
Процессы
Процессы — это акторы. Они хранят состояние между сообщениями, работают независимо от того, кто их запустил, и общаются через передачу сообщений.
local pid = process.spawn("app.workers:handler", "app:processes")
process.send(pid, "job", {task = "process_data"})
Когда вы порождаете процесс, он продолжает работать даже после завершения вашего кода. Процессы могут мониторить друг друга, связываться вместе и формировать деревья супервизии, автоматически перезапускающие упавших потомков.
Планировщик мультиплексирует тысячи процессов на пуле воркеров. Каждый процесс делает yield при ожидании I/O, позволяя другим работать.
Workflows
Workflows — для операций, которые абсолютно не могут провалиться. Они сохраняют состояние в провайдер workflows (Temporal или другие) и могут возобновиться ровно с того места после падений, перезапусков или изменений инфраструктуры.
-- Может работать днями, пережить перезапуски и никогда не потерять прогресс
workflow.execute("app.orders:process", order_id)
Компромисс — задержка. Каждый шаг записывается, поэтому workflows медленнее функций или процессов. Но для многошаговых бизнес-процессов или длительных оркестраций эта надёжность того стоит.
Сравнение
| Функции | Процессы | Workflows | |
|---|---|---|---|
| Состояние | Нет | В памяти | Персистентное |
| Время жизни | Один вызов | До exit или падения | Переживает всё |
| Коммуникация | Возвращаемое значение + сообщения | Передача сообщений | Вызовы activities + сообщения |
| Обработка сбоев | Обрабатывает вызывающий | Деревья супервизии | Автоматический retry |
| Задержка | Минимальная | Низкая | Выше |
Один код, разное поведение
Многие модули автоматически адаптируются к контексту. Например, time.sleep() в функции блокирует воркер, в процессе делает yield для работы других, а в workflow записывает таймер, который корректно воспроизводится при восстановлении.