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/bindings:erlang
Если это не должно быть чистым решением erlang, это может быть выбор.