9

免责声明:我对 Erlang 和 OTP 很陌生。

我想要一个 Erlang/OTP 中的简单 pubsub,其中进程可以在某个“集线器”订阅并接收发送到该集线器的消息副本。

我知道gen_event,但它在一个事件管理器进程中处理事件,而我希望每个订阅者都是一个独立的、自治的进程。此外,我无法接受 grokgen_event的处理程序监督。不幸的是,谷歌搜索结果充满了 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

4 回答 4

11

我最近使用gproc来实现 pubsub。自述文件中的示例可以解决问题。

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}).
于 2011-09-10T18:38:00.723 回答
10

从您的代码来看,在我看来 gen_event 处理程序是完美的匹配。

处理程序回调是从一个调度消息的中央进程调用的,但这些回调不应该做太多工作。

因此,如果您需要为订阅者提供具有自己状态的自治进程,只需在事件回调中发送消息即可。

通常这些自​​治进程是 gen_servers ,您只需从事件回调中调用 gen_server:cast 。

监督是一个单独的问题,可以通过 OTP 附带的常用监督基础设施来处理。您希望如何进行监督取决于订阅者进程的语义。如果它们都是相同的服务器,您可以使用simple_one_for_one例如。

init订阅者进程的回调中,您可以将gen_event:add_handler调用添加到事件管理器中。

如果您使用该gen_event:add_sup_handler功能来添加您的流程,如果它的语义适合您,您甚至可以使用事件管理器作为主管。

更好地理解 gen_event 的在线资源:Learn you some Erlang chapter

否则 Erlang 书籍都有一些 gen_event 介绍。可能是您在Erlang 和 OTP in Action中可以找到的最彻底的一个

哦,顺便说一句:我不会为此攻击你自己的主管。

于 2011-08-30T17:20:22.657 回答
1

一个非常简单的例子,你自己做这一切是在我的非常基本的chat_demo中,它是一个简单的基于 Web 的聊天服务器。查看chat_backend.erl(或者chat_backend.lfe如果您喜欢括号)允许用户订阅,然后他们将收到所有到达后端的消息。尽管修改很简单,但它不适合监督树(尽管它确实用于proc_lib获得更好的错误消息)。

于 2011-08-31T13:49:34.197 回答
-2

有时,我读到有关 øMQ (ZeroMQ) 的文章,它有一堆与不同编程语言的绑定。

http://www.zeromq.org/

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

如果它一定不是纯 erlang 解决方案,那么这可能是一种选择。

于 2011-08-31T06:41:34.570 回答