Динамическое изменение диспетчера Erlang для перезапуска интенсивности

Мой вопрос в том, может ли изменить пороговые значения интенсивности перезапуска уже запущенного супервизора, кроме как в сценарии обновления выпуска, и если да, то как?

Он никогда не появлялся раньше, но запустил супервизора с изначально без детей, так что другой процесс запускает детей с помощью супервизора: start_child/2, поэтому мой sup init/1 выглядит следующим образом:

init([]) ->
    RestartSt = {simple_one_for_one, 10, 10},
    ChSpec = [foo, {foo,start_link,[]}, transient, 1000, worker, [foo]}],
    {ok, {RestartSt, ChSpec}}.

Во время запуска супервизора вероятное количество детей неизвестно; конечно, он может сильно варьироваться от 10, до 10 000 или более.

Интенсивность повторения, скажем, 20 достаточно щедра для 10 детей, но, скажем, для 10 000 детей, я хотел бы иметь возможность увеличить ее... и уменьшать ее, поскольку количество детей падает из-за нормальных окончаний.

Ответ 1

Нет API для этого, поэтому я считаю, что вы придерживаетесь подхода к обновлению, если вы не хотите предлагать новый API для этого в команду OTP с помощью отправки запроса на перенос, предоставляя полный патч с изменениями кода, новыми тестами и изменениями документации.

Там также очень грязный способ взломать это, что включает в себя манипулирование внутренним статусом супервизора, и поэтому это абсолютно не то, что я бы рекомендовал для производственной системы, но я думаю, что это все еще интересно посмотреть. A supervisor сохраняет интенсивность перезапуска во внутреннем состоянии цикла. Вы можете увидеть это состояние, вызвав sys:get_state/1,2 в процессе диспетчера. Например, здесь состояние супервизора на веб-сервере Yaws:

1> rr(supervisor).
[child,state]
2> sys:get_state(yaws_sup).
#state{name = {local,yaws_sup},
       strategy = one_for_all,
       children = [#child{pid = <0.67.0>,name = yaws_sup_restarts,
                          mfargs = {yaws_sup_restarts,start_link,[]},
                          restart_type = transient,shutdown = infinity,
                          child_type = supervisor,
                          modules = [yaws_sup_restarts]},
                   #child{pid = <0.42.0>,name = yaws_server,
                          mfargs = {yaws_server,start_link,
                                                [{env,true,false,false,false,false,false,"default"}]},
                          restart_type = permanent,shutdown = 120000,
                          child_type = worker,
                          modules = [yaws_server]},
                   #child{pid = <0.39.0>,name = yaws_trace,
                          mfargs = {yaws_trace,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_trace]},
                   #child{pid = <0.36.0>,name = yaws_log,
                          mfargs = {yaws_log,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_log]}],
       dynamics = undefined,intensity = 0,period = 1,restarts = [],
       module = yaws_sup,args = []}

Первоначальная команда rr извлекает определения записей из supervisor, поэтому мы можем видеть имена полей, когда мы получаем состояние из yaws_sup, иначе мы просто получим кортеж, полный анонимных значений.

Полученное состояние показывает интенсивность в этом случае равным 0. Мы можем изменить его, используя sys:replace_state/2,3:

3> sys:replace_state(yaws_sup, fun(S) -> S#state{intensity=2} end).
#state{name = {local,yaws_sup},
       strategy = one_for_all,
       children = [#child{pid = <0.67.0>,name = yaws_sup_restarts,
                          mfargs = {yaws_sup_restarts,start_link,[]},
                          restart_type = transient,shutdown = infinity,
                          child_type = supervisor,
                          modules = [yaws_sup_restarts]},
                   #child{pid = <0.42.0>,name = yaws_server,
                          mfargs = {yaws_server,start_link,
                                                [{env,true,false,false,false,false,false,"default"}]},
                          restart_type = permanent,shutdown = 120000,
                          child_type = worker,
                          modules = [yaws_server]},
                   #child{pid = <0.39.0>,name = yaws_trace,
                          mfargs = {yaws_trace,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_trace]},
                   #child{pid = <0.36.0>,name = yaws_log,
                          mfargs = {yaws_log,start_link,[]},
                          restart_type = permanent,shutdown = 5000,
                          child_type = worker,
                          modules = [yaws_log]}],
       dynamics = undefined,intensity = 2,period = 1,restarts = [],
       module = yaws_sup,args = []}

Наш второй аргумент sys:replace_state/2 принимает запись состояния как аргумент и меняет его поле intensity на 2. Функции sys:replace_state/2,3 возвращают новое состояние, и, как вы можете видеть в конце результата здесь, intensity теперь равен 2 вместо 0.

Как поясняет документация sys:replace_state/2,3, эти функции предназначены только для целей отладки, поэтому использование их для этого в производственной системе определенно не является чем-то, что я рекомендую. Второй аргумент replace_state показывает, что этот подход требует знания деталей внутренней записи состояния supervisor, которую мы получили здесь с помощью команды оболочки rr, поэтому, если эта запись когда-либо изменится, этот код может остановиться за работой. Еще более хрупкой будет обработка записи состояния supervisor в виде кортежа и подсчет поля intensity в определенной позиции кортежа, чтобы вы могли изменить его значение. Поэтому, если вам действительно нужна эта функция изменения интенсивности перезапуска супервизора, вам лучше всего в долгосрочной перспективе предложить команде OTP, чтобы она была добавлена; если вы собираетесь воспользоваться этим маршрутом, я рекомендую сначала предложить идею в списке рассылки erlang-questions для оценки процентов.

Ответ 2

Одним из решений было бы вложение ваших наблюдателей. Но главный вопрос заключается в том, чего вы хотите достичь благодаря этим интенсивностям перезапуска. Интенсивность, когда вы хотите убить супервизора, должна быть признаком чего-то очень неправильного, например. необходимый ресурс неожиданно недоступен.