Как навести порядок в хаосе микросервисов с помощью Jido
Знакомая история: вы начинаете проект на Elixir, радуетесь мощи OTP и легкости создания процессов. Но проходит полгода, и ваш проект превращается в зоопарк из сотен GenServer-ов. У каждого свои форматы сообщений, свои способы обработки ошибок и хитровыдуманные схемы отслеживания дочерних процессов. В какой-то момент вы понимаете, что в пятый раз переписываете один и тот же код для маршрутизации сигналов или управления жизненным циклом агента.
Именно эту проблему пытается решить Jido. Это не просто очередная библиотека, а попытка формализовать паттерн автономных агентов в Elixir, сохранив при этом все преимущества функционального программирования.
Что такое Jido и зачем оно в Elixir
Название Jido (自動) переводится с японского как «автоматический». По сути, это фреймворк для создания автономных агентов. Если GenServer дает нам примитив для управления состоянием, то Jido накладывает на него структуру.
Главная фишка здесь в разделении чистой логики и побочных эффектов. В Jido агент — это неизменяемая структура данных. Вы вызываете функцию cmd/2, передаете туда текущее состояние и команду, а на выходе получаете обновленного агента и список «директив». Директивы — это просто описание того, что нужно сделать: отправить письмо, запустить другой процесс или сохранить данные. Сама функция cmd/2 остается чистой, что делает тестирование агентов элементарным делом. Вам не нужно запускать процессы и ждать ответов в тестах, достаточно проверить возвращаемую структуру.
Как это выглядит на практике
Давайте посмотрим на классический пример с простым счетчиком. Сначала опишем действие (Action):
defmodule MyApp.Actions.Increment do
use Jido.Action,
name: "increment",
schema: [amount: [type: :integer, default: 1]]
def run(params, context) do
current = context.state[:count] || 0
{:ok, %{count: current + params.amount}}
end
end
Теперь создадим самого агента:
defmodule MyApp.CounterAgent do
use Jido.Agent,
name: "counter",
schema: [count: [type: :integer, default: 0]],
signal_routes: [{"increment", MyApp.Actions.Increment}]
end
Использование в чистом функциональном стиле выглядит так:
agent = MyApp.CounterAgent.new()
{agent, directives} = MyApp.CounterAgent.cmd(agent, {MyApp.Actions.Increment, %{amount: 5}})
# agent.state.count теперь равен 5
Почему бы не использовать обычный GenServer
Этот вопрос возникает первым. Автор проекта Mike Hostetler приводит наглядное сравнение. В сыром OTP вам приходится каждый раз заново изобретать форму сообщений, мешать бизнес-логику с колбэками GenServer и вручную следить за иерархией процессов.
Jido предлагает стандарт:
- Сигналы (на базе CloudEvents) вместо произвольных сообщений.
- Действия (Actions) как переиспользуемые паттерны команд.
- Директивы вместо разбросанных по коду
sendилиRepo.insert. - Встроенная иерархия «родитель-ребенок» для агентов.
Это напоминает переход от голого SQL к полноценной ORM или от манипуляций с DOM к реактивным фреймворкам. Вы теряете в «свободе» делать всё как угодно, но выигрываете в предсказуемости и скорости разработки.
Экосистема и возможности
Jido — это не монолит. Проект разбит на несколько пакетов, которые можно подключать по мере необходимости.
Например, jido_ai добавляет интеграцию с LLM, превращая ваших агентов в умных помощников, способных использовать инструменты. jido_signal отвечает за маршрутизацию сообщений, а jido_action позволяет создавать валидируемые и композируемые действия.
Интересна концепция State Operations. Это внутренние операции над состоянием (SetState, DeleteKeys, SetPath), которые применяются внутри cmd/2. Они позволяют глубоко модифицировать состояние агента, не превращая код в мешанину из put_in и update_in.
Для продакшена предусмотрен AgentServer. Это обертка над GenServer, которая умеет исполнять те самые директивы, управлять жизненным циклом и даже восстанавливать агентов после перезагрузки (через механизмы гибернации и «оттаивания» состояния).
Кому стоит попробовать Jido
Если вы пишете простое CRUD-приложение, Jido, скорее всего, будет избыточным. Но проект станет спасением, если вы строите:
- Системы со сложными рабочими процессами (Workflows), где много промежуточных состояний.
- Многоагентные системы, где сущности должны активно общаться друг с другом.
- Приложения, интегрированные с ИИ, где нужно четко контролировать, какие действия разрешено выполнять модели.
Проект еще достаточно молодой (версия 2.0 вышла недавно), но архитектурно он выглядит очень зрелым. Он берет идеи из Elm и Redux и переносит их на благодатную почву Elixir/OTP. Если вам надоело отлаживать гонки состояний в своих процессах, Jido — отличный повод пересмотреть свой подход к архитектуре.
Начать проще всего через установщик Igniter: mix igniter.install jido. Он сам создаст нужные модули и пропишет их в дерево супервизии, так что можно будет сразу перейти к экспериментам.
