Какие типы стратегий у 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 Один тип, создаётся динамически Сессии, подключения, временные воркеры
--- --- ---

Выбор стратегии зависит от характера приложения, связей между процессами и требований к отказоустойчивости.