Erlang: простой pubsub для процессов - мой подход в порядке? - PullRequest
8 голосов
/ 30 августа 2011

Отказ от ответственности: я довольно новичок в Erlang и OTP.

Мне нужен простой pubsub в Erlang / OTP, где процессы могут подписаться на каком-то «хабе» и получать копии сообщений, которые были отправлены на этот хаб.

Я знаю о gen_event, но он обрабатывает события в одном процессе менеджера событий, в то время как я хочу, чтобы каждый подписчик был отдельным, автономным процессом. Кроме того, я не смог уловить надзор за обработчиками gen_event. К сожалению, результаты Google были полны ссылок XMPP (Ejabberd) и RabbitMQ, поэтому я не нашел ничего подходящего для моей идеи.

Моя идея заключается в том, что такая модель pubsub легко отображается в дереве наблюдения. Поэтому я решил расширить супервизор (gen_server под колпаком), чтобы иметь возможность отправлять кастовое сообщение всем его дочерним элементам.

Я взломал это в своём быстром и грязном пользовательском поведении диспетчера:

-module(dispatcher).
-extends(supervisor).
-export([notify/2, start_link/2, start_link/3, handle_cast/2]).

start_link(Mod, Args) ->
    gen_server:start_link(dispatcher, {self, Mod, Args}, []).

start_link(SupName, Mod, Args) ->
    gen_server:start_link(SupName, dispatcher, {SupName, Mod, Args}, []).

notify(Dispatcher, Message) ->
    gen_server:cast(Dispatcher, {message, Message}).

handle_cast({message, Message}, State) ->
    {reply, Children, State} = supervisor:handle_call(which_children, dummy, State),
    Pids = lists:filter(fun(Pid) -> is_pid(Pid) end,
                 lists:map(fun({_Id, Child, _Type, _Modules}) -> Child end,
                           Children)),
    [gen_server:cast(Pid, Message) || Pid <- Pids],
    {noreply, State}.

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

Может ли кто-нибудь, пожалуйста, раскритиковать (или одобрить) мой подход и / или порекомендовать несколько альтернатив?

Ответы [ 4 ]

11 голосов
/ 10 сентября 2011

Я недавно использовал gproc для реализации pubsub.Пример из readme делает свое дело.

subscribe(EventType) ->
    %% Gproc notation: {p, l, Name} means {(p)roperty, (l)ocal, Name}
    gproc:reg({p, l, {?MODULE, EventType}}).

notify(EventType, Msg) ->
    Key = {?MODULE, EventType},
    gproc:send({p, l, Key}, {self(), Key, Msg}).
10 голосов
/ 30 августа 2011

Из вашего кода мне кажется, что обработчики gen_event идеально подходят.

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

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

Обычно эти автономные процессы бывают gen_servers, и вы просто вызываете gen_server: cast из ваших обратных вызовов событий.

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

В обратном вызове init процессов подписчика вы можете поместить вызовы gen_event:add_handler, добавляющие их в менеджер событий.

Вы даже можете использовать менеджер событий в качестве супервизора, если используете функцию gen_event:add_sup_handler для добавления своих процессов, если семантика этого вам подходит.

Интернет-ресурсы для лучшего понимания gen_event: Познакомьтесь с главой по эрлангу

В противном случае книги Эрланга имеют некоторое введение в gen_event. Вероятно, наиболее тщательный, который вы можете найти в Erlang и OTP в действии

Да и кстати: я бы не стал взламывать ваших собственных руководителей для этого.

1 голос
/ 31 августа 2011

Очень простой пример, где вы все делаете сами, находится в моем простом chat_demo , который представляет собой простой веб-сервер чата. Посмотрите на chat_backend.erl (или chat_backend.lfe, если вам нравятся круглые скобки), которое позволяет пользователям подписаться , и тогда им будут отправляться все сообщения, поступающие на сервер. Он не вписывается в деревья наблюдения, хотя модификация проста (хотя для получения более качественных сообщений об ошибках используется proc_lib).

0 голосов
/ 31 августа 2011

Иногда назад я читал о øMQ (ZeroMQ), который имеет связки с различными языками программирования.это не должно быть чисто решение Эрланга, это может быть выбор.

...