Erlang: простой pubsub для процессов - мой подход в порядке?

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

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

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

моя идея заключается в том, что такая модель pubsub легко сопоставляется с деревом наблюдения. Поэтому я подумал о расширении супервизора (a 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 ответов


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

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

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

обычно эти автономные процессы будут gen_servers, и вы просто вызовете gen_server: cast из вашего события обратный вызов.

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

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

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

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

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

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


Я недавно использовал 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}).

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


иногда я читал о øMQ (ZeroMQ), который имеет кучу привязок к различным языкам программирования.

http://www.zeromq.org/

http://www.zeromq.org/bindings:erlang

Если это не должно быть чистым решением erlang, это может быть выбор.