Супервизор не перезагружается на econnrefused (кидается в init / 1)

У меня есть init функция gen_server, которую я подключаю к rabbitmq. Когда все в порядке, он работает отлично, однако при сбое подключения к rabbitmq и я вызываю exit процесс не перезапускается.

Я хочу, чтобы супервизор перезапустил этот процесс после того, как я позвоню exit.

Концептуально моя функция init выглядит так:

init(_Args) ->
  process_flag(trap_exit, true),
  case connect() of
    {error, econnrefused} ->
            timer:sleep(1000),
            exit(econnrefused);
    {ok, Connection} ->
            .....
  end,
  {ok, {}}.

А вот и мой руководитель:

-module(tasks_manager_sup).
-behaviour(supervisor).
-export([start_link/0]).
-export([init/1]).
-define(SERVER, ?MODULE).

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

init([]) ->
    {ok,
     {#{strategy => one_for_one, 
        intensity => 50,
        period => 10},
      [#{id => tasks_manager_serv_id,
         start => {tasks_manager_serv, start_link, []},
         restart => permanent,
         shutdown => brutal_kill,
         type => worker,
         modules => [tasks_manager_serv]}]}}.

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

Starting {global,tasks_da_serv} (<0.479.0>)
Starting {global,tasks_manager_serv} (<0.483.0>)

 =INFO REPORT==== 9-Jun-2017::09:52:46 ===
     application: tasks
     exited: {{shutdown,
                  {failed_to_start_child,tasks_manager_sup_id,
                      {shutdown,
                          {failed_to_start_child,tasks_manager_serv_id,
                              econnrefused}}}},
              {tasks_app,start,[normal,[]]}}
     type: permanent
 {"Kernel pid terminated",application_controller,"{application_start_failure,tasks,{{shutdown,{failed_to_start_child,tasks_manager_sup_id,{shutdown,{failed_to_start_child,tasks_manager_serv_id,econnrefused}}}},{tasks_app,start,[normal,[]]}}}"}
 Kernel pid terminated (application_controller) ({application_start_failure,tasks,{{shutdown,{failed_to_start_child,tasks_manager_sup_id,{shutdown,{failed_to_start_child,tasks_manager_serv_id,econnrefu

Я также пробовал передать сообщение в self() (из функции init) и подключиться к кролику в handle_cast, но это тоже не работает.

Я все еще изучаю Erlang / OTP, так что простите меня, если я спрашиваю о чем-то очевидном, но я не смог найти в документации ответа на свою проблему.


person Szymon Wygnański    schedule 09.06.2017    source источник
comment
Я не могу найти это задокументированным, но похоже, что супервизор не перезапускает процесс, потому что он завершается через init. Он перезапустит его для меня, если я добавлю self() ! connect, а затем выйду через handle_info(connect, ...).   -  person Dogbert    schedule 09.06.2017
comment
@Dogbert, руководитель : start_link () docs? --- ›Если супервизор и его дочерние процессы успешно созданы (то есть, если все функции запуска дочерних процессов возвращают {ok, Child}, {ok, Child, Info} или игнорируют), функция возвращает { ok, Pid}, где Pid - это pid супервизора .... Если Module: init / 1 не работает или возвращает неверное значение, эта функция возвращает {error, Term}, где Term - это термин с информацией об ошибке, и руководитель прекращает работу по причине Срок действия   -  person 7stud    schedule 10.06.2017
comment
Другими словами, вы должны иметь возможность запускать потомков супервизора в первый раз, иначе процесс супервизора не будет создан.   -  person 7stud    schedule 10.06.2017
comment
@ 7stud Это не supervisor, который не начинается в вопросе OP, а gen_server, который запускается им.   -  person juan.facorro    schedule 10.06.2017
comment
Дочерний запуск супервизора должен быть успешным, но ничто не мешает вам разрабатывать init/1 попытки подключиться несколько раз, прежде чем окончательно сдаться. Если супервизор запускает других дочерних элементов, которые ожидают, что средство rabbitmq будет доступно, то это, вероятно, лучше, чем позволить ему запускаться и асинхронно пытаться подключиться ... Вам действительно нужно повторить попытку? Если вы подключаетесь без повторной попытки, все приложение затем относительно быстро выходит из строя из-за недоступности внешнего ресурса, и это ясно для администраторов, которые могут с этим справиться.   -  person Michael    schedule 11.06.2017
comment
@Michael Иногда могут случиться непредвиденные обстоятельства, и соединение прервется (кабельная обезьяна IDK?). Так что перезапустить его несколько раз может быть хорошей идеей.   -  person Szymon Wygnański    schedule 12.06.2017


Ответы (1)


Благодаря комментариям под вопросом я смог его решить. В основном проблема заключалась в том, что процесс не был запущен правильно, потому что exit(econnrefused) находился в init/1 функции. Вот почему супервизор не перезапускал процесс - он не перезапускает процессы, которые не инициализировались.

Теперь я отправляю сообщение self(), а затем ловлю его в hangle_info/2 вот так:

init(_Args) ->
    process_flag(trap_exit, true),
    io:format("Starting ~p (~p)~n", [{global, ?MODULE}, self()]),
    self() ! connect,
    {ok, {}}.

handle_info(connect, State) ->
    {ok, Connection, Channel} = establish_rabbit_connection(),
    {noreply, #state{connection = Connection, channel = Channel}};
person Szymon Wygnański    schedule 12.06.2017