2017-01-30 15 views
1

У меня есть диспетчер с :simple_one_to_one стратегия повторного запуска, что происходит с детьми, когда я звоню Supervisor.stop(sup)?Как руководитель эликсира останавливает детей на остановке?

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

ответ

1

Ivan. Я думаю, вы хотите уловить выходы своих рабочих. Если вы их не поймаете, их просто убивают. Вот пример того, что я имею в виду:

defmodule SupervisorStop do 
    use Application 

    def start(_type, _args) do 
    import Supervisor.Spec, warn: false 

    children = [ worker(SupervisorStop.Worker, []) ] 

    opts = [strategy: :simple_one_for_one, name: SupervisorStop.Supervisor] 
    Supervisor.start_link(children, opts) 
    end 
end 

defmodule SupervisorStop.Worker do 
    use GenServer 
    require Logger 

    def start_link(args) do 
    GenServer.start_link(SupervisorStop.Worker, args, []) 
    end 

    def init(trap_exit) do 
    Logger.info "#{inspect self} trap_exit: #{inspect trap_exit}" 
    if trap_exit do 
     Process.flag(:trap_exit, true) 
    end 
    {:ok, []} 
    end 

    def terminate(reason,_state) do 
    Logger.info "terminating: #{inspect self}: #{inspect reason}" 
    :ok 
    end  
end 

если я запускаю это в IEX вот что происходит:

09:55:26 [email protected] test0 > iex -S mix 
Erlang/OTP 18 [erts-7.2.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] 

Compiling 1 file (.ex) 
Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help) 
iex(1)> Supervisor.start_child(SupervisorStop.Supervisor, [true]) 

09:59:16.086 [info] #PID<0.102.0> trap_exit: true 
{:ok, #PID<0.102.0>} 
iex(2)> Supervisor.start_child(SupervisorStop.Supervisor, [false]) 
{:ok, #PID<0.104.0>} 

09:59:21.113 [info] #PID<0.104.0> trap_exit: false 
iex(3)> Supervisor.stop(SupervisorStop.Supervisor) 

09:59:35.702 [info] terminating: #PID<0.102.0>: :shutdown 
:ok 
iex(4)> 
09:59:35.710 [info] Application test0 exited: normal 

nil 

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

09: 59: 16,086 [Информация] #PID < 0.102.0> trap_exit: правда ... 09: 59: 35,702 [Информация] завершение: #PID < 0.102.0>: : выключение

другой pid не сообщает о его завершении вызова. Это потому, что

09: 59: 21,113 [Информация] #PID < 0.104.0> trap_exit: ложные

Существует очень полезная статья, если вы действительно хотите, чтобы понять все различные комбинации:

http://crypt.codemancers.com/posts/2016-01-24-understanding-exit-signals-in-erlang-slash-elixir/

+0

Ну, я закончил работу с GenServer.stop (c hild) на всех дочерних элементах диспетчера через Task.async и после этого останавливает Супервизора. Моя основная цель состояла в том, чтобы позволить серверам завершить все, что они делали, но не допустить получения большего количества сообщений. Ваш эксперимент доказывает, что детей жестоко убивают, когда Супервизор останавливается, как я подозревал. Благодаря! –

1

Перефразируя большую статью: «Кто контролирует супервайзеры»

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

Короче говоря, если вы хотите грациозно выключение работника:

  • Сделать ловушка выходит
  • Ручка выключения в terminate функции

Источник: http://learnyousomeerlang.com/supervisors