Какие типы стратегий у Supervisor?
В Elixir Supervisor использует стратегии перезапуска дочерних процессов для обеспечения надёжности и отказоустойчивости. Эти стратегии определяют, какие процессы нужно перезапускать в случае сбоя одного из них. От правильного выбора стратегии зависит поведение всей системы в аварийных ситуациях.
Существует четыре основных типа стратегий:
1. :one_for_one
Суть:
Если один дочерний процесс завершился с ошибкой, перезапускается только он.
Применение:
Подходит, когда процессы независимы друг от друга и сбой одного не влияет на других.
Пример:
Supervisor.init(children, strategy: :one_for_one)
Поведение:
-
P1, P2, P3 — независимые процессы.
-
Если P2 падает, перезапускается только P2.
Когда использовать:
- Web-сессии, изолированные обработчики задач, процессы без общей внутренней логики.
2. :one_for_all
Суть:
Если один дочерний процесс завершается с ошибкой, перезапускаются все дочерние процессы.
Применение:
Подходит, когда процессы тесно связаны между собой, и работа одного зависит от состояния других.
Пример:
Supervisor.init(children, strategy: :one_for_all)
Поведение:
-
P1, P2, P3 — связанные процессы.
-
Если падает P2, Supervisor завершает P1 и P3, затем перезапускает все три.
Когда использовать:
-
Процессы, которые совместно используют ресурсы или имеют общие данные в состоянии.
-
Например, процесс подключения к БД и кэш-менеджер, синхронизирующий данные.
3. :rest_for_one
Суть:
Если падает один процесс, Supervisor завершает и перезапускает этот и все процессы, запущенные после него.
Применение:
Когда порядок запуска важен, и последующие процессы зависят от предыдущих.
Пример:
Supervisor.init(children, strategy: :rest_for_one)
Поведение:
-
Допустим, Supervisor запускает процессы в порядке: P1 → P2 → P3.
-
Если падает P1 — перезапускаются P1, P2, P3.
-
Если падает P2 — перезапускаются P2 и P3.
-
Если падает P3 — перезапускается только P3.
Когда использовать:
-
В случаях зависимостей вниз по цепочке запуска.
-
Например, процессы, которые строятся поверх других и могут нарушиться, если предыдущий выйдет из строя.
4. :simple_one_for_one (устарела, используется DynamicSupervisor)
Суть:
Предназначалась для динамического запуска однородных дочерних процессов с одинаковой спецификацией.
Поведение:
-
Не имеет фиксированного списка дочерних процессов.
-
Все дочерние процессы однотипны и запускаются вручную через Supervisor.start_child.
Пример:
В более старых версиях Elixir использовали:
Supervisor.init(\[{MyWorker, \[\]}\], strategy: :simple_one_for_one)
Заменено на:
Сейчас используется DynamicSupervisor с гибкой и мощной моделью управления динамическими дочерними процессами:
DynamicSupervisor.start_child(MySupervisor, {MyWorker, args})
Когда использовать:
- Когда нужно создавать процессы на лету — например, для пользователей чата или веб-сессий.
Поведение Supervisor при частых сбоях
Supervisor имеет параметры:
-
max_restarts — максимальное число рестартов,
-
max_seconds — период времени, в течение которого учитываются рестарты.
Если количество рестартов превышает max_restarts за max_seconds, Supervisor сам завершает работу, чтобы избежать бесконечного цикла сбоев.
Supervisor.start_link(children, strategy: :one_for_one, max_restarts: 3, max_seconds: 5)
Таблица сравнения стратегий
Стратегия | Что перезапускается при сбое? | Пример использования |
---|---|---|
:one_for_one | Только упавший процесс | Независимые задачи, воркеры |
--- | --- | --- |
:one_for_all | Все дочерние процессы | Связанные модули, общее состояние |
--- | --- | --- |
:rest_for_one | Упавший и все после него | Зависящие по порядку старта |
--- | --- | --- |
:simple_one_for_one | Один тип, создаётся динамически | Сессии, подключения, временные воркеры |
--- | --- | --- |
Выбор стратегии зависит от характера приложения, связей между процессами и требований к отказоустойчивости.