2016-01-06 2 views
4

В соответствии с руководством Erlang/OTP, если я добавлю ребенка к супервизору с использованием supervisor:start_child, а диспетчер выйдет из строя, ребенок не будет автоматически перезагружен.Автоматический перезапуск динамически добавленных детей супервизора

(http://www.erlang.org/doc/design_principles/sup_princ.html#id73986)

Существует простой обходной путь для этого, или я должен вручную сохранить динамически добавленные ребенок каким-то образом и управлять повторным запуском самостоятельно? (Мой руководитель имеет надзорный надзор, поэтому это возможно, хотя и не очень элегантно.)

ответ

5

Ваши руководители - это процессы, как и любые другие, причем разница заключается в том, что они являются системными процессами (все это trap_exit). Когда он умирает, внутреннее состояние, которое оно держит, идет с ним - пуф!

ЭТО хорошая вещь

Восстановление наблюдателя умирает такой же, как для работника умирает (супервизор является работником другого диспетчера, в конце концов). Вероятно, вы столкнулись с тем, что структура вашего дерева наблюдения не совсем соответствует вашим потребностям. Если вам нужны задания для сохранения, если их руководитель умирает, то эти задачи ближе к ядру аварии программы, чем вы их разместили, а это означает, что они должны быть детьми чего-то выше по цепочке или (скорее), что вы переоцениваете их важность для системы.

Самая распространенная причина, по которой я начинаю беспокоиться о том, чтобы убедиться, что процесс сохраняется, когда я дал ему слишком большую ответственность. Всякий раз, когда я нахожу себя задающим вопросы типа «как я могу убедиться, что ребенок перезапущен супервизором, если супервизор сработает», я останавливаюсь на несколько минут и тщательно обдумываю, почему я задаю этот вопрос - этот всегда ведет меня к открытию архитектурной проблемы (и фиксация ее всегда, кстати, делает что-то другое в остальной части системы более разумной).

Реальный пример из жизни:

В бизнес-сервер был технологический модуль, который изначально был «только соединение с клиентом». Он превратился в управление сетевым подключением к клиенту, перевод между внутренними значениями Erlang и значениями внешнего протокола и представление существования клиента (присутствие, аудиторская активность, авторизация, чат и т. Д.) Внутри системы. Из-за ведения аудита я начал задаваться вопросом о том же, что и вы: если sup dies, как я могу закрыть то, что коснулся клиент и т. Д.?

Затем произошла ошибка, которая была проигнорирована: одновременный вход с нескольких устройств стал требованием. Вход в несколько устройств является странным, когда есть несколько экземпляров одного и того же «клиента» и т. Д. (А не только несколько процессов подключения, используемых одним клиентским процессом). Разделение этих задач на разные процессы (а не только на модули) значительно упростило ситуацию и сделало структуру восстановления состояния более очевидной и понятной.

Добавление

ОП спросил: «Так почему же разница тогда между статическими и динамическими детьми в связи с этим?» Хороший вопрос.Почему do у нас есть определения статического ребенка, команды динамического контроля, такие как supervisor:start_child/2 и и те странные simple_one_for_one супервизоры?

Ключ в ваших случаях использования. Предположим, у меня есть игровой сервер, которому нужно всегда имеют доступ к лобби, чтобы игроки могли входить в систему, общаться в чате, просматривать веб-сайт арсенала, гипсовать форумы с вопросами о нобе и анти-девелоперами и обычно тратить время другими способами, только периферийно связаны с реальной игрой. We never хотите сбой в одном, чтобы сразу же их снести, но, возможно, мы хотим сказать разные запущенные сервисы для прослушивания в сети или прекратить прием соединений по требованию. Однако реальные игровые сферы существуют в своих отдельных ветвях дерева наблюдения - если один из них идет вниз, мы не хотим, чтобы он взял с собой все остальное, и мы, конечно, не хотим потерять весь кластер ,

Итак, как бы мы это структурировали? Все базовые службы будут записываться непосредственно в определения дочернего дерева супервизора - нет динамизма там, если мы не вызываем его вручную. Всякий раз, когда мы запускаем систему, они появляются. Так как у нас может быть произвольно много игровых сфер, хотя определение области внутренне структурировано как в основном статически определенное дерево наблюдения, каждый супервизор уровня уровня является дочерним элементом простого администратора_объекта, который управляет всеми сферами (поэтому, если этот диспетчер идет вниз, тогда POOF! Все вернулись в холл, наверное, досадно). Режимы могут быть запущены на основе наших команд, файла настроек или данных db или их комбинации.

Может быть, хорошо отложить начало услуг внешней сети. У нас, вероятно, есть несколько важных задач запуска, когда инициация системы и слушателей, вероятно, придется начинать с различных узлов в кластере. Чтобы избежать прямого нажатия на систему с сетевыми подключениями, дайте нам время, чтобы проверить систему или запустить тесты, и иметь возможность установить систему в какой-то конкретный режим (бенчмаркинг, тестирование, турнир или что-то еще), которое мы, возможно, пожелаем для задержки запуска внешних сетевых сервисов. То есть мы вынуждаем систему ждать команды, которую мы отправляем, прежде чем она откроет карнавальные двери для немытых масс. Мы завершаем команду в каком-то простом вызове, который мы можем получить из оболочки или сети (например, waste_of_youth:tempt_souls(Node, Port, Cert)), но что произойдет в результате этого - это последовательность вызовов supervisor:start_child/2 - и они являются динамическими.

Итак, что произойдет, если менеджер сетевого сервиса умрет? Соединения идут POOF! Они не появятся снова, пока мы не скажем им (не только активные соединения, но и слушатели, которые, возможно, умерли независимо от активных подключений, в зависимости от того, с чем столкнулся диспетчер), потому что система спроектирована именно так. Мы могли бы сделать все возможное, чтобы смягчить это, хотя это проблема. У нас может быть процесс, задачей которого является знать и отслеживать последнее состояние какой-либо конкретной службы, например, внешние сети, и если она неожиданно неожиданно инициирует вызов. Но это обычно не то, что вы хотите - большую часть времени, когда вам нужны службы, автоматически перезапускаются, вы хотите, чтобы статические определения постоянных служб были прочитаны в системе при запуске.

Выше я упомянул о разных режимах, мы можем захотеть включить сервер при запуске. Удобно отделять определения дочерних элементов от остальной части кода, чтобы, когда я говорю «начать в режиме тестовой игры», он загружает несколько разных расширений определений супервизора (и будет придерживаться этого, если мы не будем с ним связываться). Если я скажу «начать в режиме производства», возможно, мы загрузим определения для детей, которые включают в себя статически определенные постоянные обработчики сетевых сервисов. Набор определений супервизора для каждого случая - и таким образом вы можете легко создавать профили обслуживания.Эти динамические команды диспетчера - это то, что позволяет вам вручную переключаться между состояниями службы или делегировать этот процесс переключения командам, которые вы определяете где-то в своем коде.

+0

Так почему же разница между статическими и динамическими детьми в этом отношении? (Обратите внимание, что мы не говорим о постоянстве дочерних состояний, я просто хочу, чтобы они были перезапущены (с чистыми состояниями) с супервизором.) – egbokul

+0

@GaborKulcsar Потому что иногда вам нужны супервизоры, чтобы иметь возможность делать вещи на лету например, внешнюю инструкцию - но * большую часть времени, когда вам нужны либо статически определенные дети (ваши основные системные службы, другие супервизоры, слушатели и т. д.), либо простой суперпользователь simple_one_for_one, который порождает армию изначально идентичных детей (сетевые подключения, обработчики ресурсов клиента, задания с успешной или аварийной остановкой и т. д.). Я обновлю пример того, почему и где каждый полезен, если я получаю некоторое время. – zxq9

+0

@GaborKulcsar Я добавил об этом. Это не очень лаконично, и, надеюсь, это не смущает. Я, вероятно, отредактирую его немного на днях для ясности. Извините, что так долго - у меня не было времени писать короче вечером. – zxq9