Запуск и завершение дочернего элемента супервизора simple_one_for_one

У меня есть простое приложение target_interceptor, которое после получения сообщений о регистрации и отмене регистрации запускает или завершает работу под simple_one_for_one rpc_server_supervisor.

Код супервайзера rpc_server_supervisor:

init([]) ->
    MaxRestart = 5,
    MaxTime = 3600,
    {ok, {{simple_one_for_one, MaxRestart, MaxTime},
            [{rbmq_rpc_server, 
                {rbmq_rpc_server, start_link, []},
                temporary,
                10000,
                worker,
                [rbmq_rpc_server]}]}}.

зарегистрировать сообщение target_interceptor:

handle_cast({register, Args}, S = #state{channel = Channel, supervisor=Sup, refs=R, qs_link = QSLinks}) ->
    {Connection, QueueName, Node} = Args,   
    {Ok, Pid} = supervisor:start_child(Sup, [Connection, QueueName, Node]),
    Ref = erlang:monitor(process, Pid),
{noreply, S#state{refs=gb_sets:add(Ref,R), qs_link=orddict:append(binary_to_list(QueueName),Pid,QSLinks)}};

сообщение об отмене регистрации target_interceptor:

handle_cast({unregister,{QueueName}}, S = #state{supervisor = Sup, qs_link = QSLinks}) ->
    Pid = orddict:fetch(QueueName,QSLinks) 
    case supervisor:terminate_child(Sup,Pid) of
         ok -> Success = true;
         Error -> io:format("Error ~p~n",[Error]),
                  Success = false
    end,
{noreply, S#state{qs_link=orddict:erase(QueueName,QSLinks)}}

моя версия Erlang: R15B01

Первая проблема заключается в том, что при обработке действия регистрации кортеж {OK, Pid} = {error, ‹0.57.0>}; хотя это указывает на то, что что-то пошло не так, gen_server rbmq_rpc_server на Pid 57 работает правильно и отвечает на сообщения. Почему возвращаемое значение функции start_child является ошибкой? Что пошло не так?

Вторая проблема связана с обработкой действия отмены регистрации, когда supervisor: terminate_child (Sup, Pid) возвращает {error, simple_one_for_one), хотя я ссылаюсь на Pid, ​​а не на ChildID. Почему он ведет себя так и как я могу динамически и индивидуально завершить дочерние элементы моего супервизора?

РЕДАКТИРОВАТЬ: И target_interceptor, и rpc_server_supervisor контролируются rbmq_sup_sup супервайзером:

init({Nodeid, Node}) ->
    MaxRestart = 1,
    MaxTime = 3600,
    {ok, {{rest_for_one, MaxRestart, MaxTime},
            [{server,
                {target_interceptor, start_link, [target, self(), {Nodeid, Node}]},
                permanent,
                5000,
                worker,
                [target_interceptor]}]}}.

РЕДАКТИРОВАТЬ: rpc_server_supervisor вызывается в функции target_interceptor init () (Sup здесь - супервизор rbmq_sup_sup):

handle_info({start_worker_supervisor, Sup}, S = #state{}) ->
    {ok, Pid} = supervisor:start_child(Sup, ?SPEC),
    link(Pid),
    {noreply, S#state{sup=Pid}};

-define(SPEC,
        {rpc_server_sup,
            {rpc_server_sup, start_link, []},
            temporary,
            10000,
            supervisor,
            [rpc_server_sup]}).

person Zuzana    schedule 14.10.2014    source источник


Ответы (1)


Я буду добавлять к этому, когда у меня будет время.

Во-первых, {Ok,Pid} соответствует любому кортежу, даже {error,Error}, поэтому вызов переменной Ok может быть не лучшим выбором.

Быстрый вопрос: в handle_cast({register,Args}, ... вы делаете binary_to_list(QueueName) для ключа, а в handle_cast({unregister,{QueueName}}, ... вы просто используете QueueName для ключа. Почему? Почему вы храните список идентификаторов для каждого QueueName, поскольку отмена регистрации, кажется, очищает их все? Это также будет означать, что когда вы сделаете Pid = orddict:fetch(QueueName,QSLinks) Pid, ​​будет список идентификаторов, а не один.

В rbmq_sup_sup вы запускаете только target_interceptor.

Зарегистрированы ли rbmq_rpc_server процессы?

РЕДАКТИРОВАТЬ:

Я думаю, что причина ошибки при выполнении unregister заключается в том, что вы сохранили pid с orddict:append/3, который сохраняет значение в списке даже в первый раз, в то время как вы получаете значение с orddict:fetch/2, которое возвращает все list в этом случае. Итак, Pid - это список. Затем вы пытаетесь убить ребенка с помощью Pid, который представляет собой список pid, а не pid, на который supervisor:terminate_child/2 жалуется.

Если у вас только один pid на QueueName, тогда вам следует использовать orddict:store(binary_to_list(QueueName), Pid, QSLinks). Тогда orddict:fetch/2 вернет pid.

P.S. Идея orddict:append/3 заключается в том, что вы можете добавить больше значений к одному и тому же ключу, и он хранит список всех значений.

person rvirding    schedule 14.10.2014
comment
Спасибо за ваши замечания, но это не вызывает у меня проблем 1.) Кортеж {Ok, Pid} существует только для демонстрации 2.) При приведении регистра QueueName имеет двоичную форму, а в формате отмены регистрации - список, я должен объединить его для удобства чтения 3.) Я перечисляю Pid, ​​чтобы иметь возможность отменить регистрацию нужного процесса при получении сообщения. Сообщение (un) register приходит через канал rbmq к target_interceptor, используется handle_info (# 'basic.deliver', # 'amqp_msg') и отбрасывает (un) сообщения регистрации с соответствующими QueueNames - person Zuzana; 14.10.2014
comment
4.) Для каждого QueueName существует только один процесс, поэтому каждое QueueName уникально и может быть завершено с помощью ссылки Pid; 5.) rbmq_rpc_server запускается в функции инициализации target_interceptor, поэтому он имеет ссылку на супервизор, а target_interceptor может запускать / завершать дочерние элементы супервизора по запросу. - person Zuzana; 14.10.2014