Erlang:用于流程的简单pubsub—;我的方法行吗?

Erlang:用于流程的简单pubsub—;我的方法行吗?,erlang,publish-subscribe,otp,extending,Erlang,Publish Subscribe,Otp,Extending,免责声明:我对Erlang和OTP非常陌生 我想要一个Erlang/OTP中的简单pubsub,其中进程可以在某个“中心”订阅并接收发送到该中心的消息副本 我知道gen_事件,但它在单个事件管理器进程中处理事件,而我希望每个订阅者都是一个独立的、自治的进程。此外,我无法浏览gen_事件的处理程序。不幸的是,谷歌搜索结果充满了XMPP(Ejabberd)和RabbitMQ链接,所以我没有找到任何与我的想法相关的内容 我的想法是这样的子模型无缝地映射到监控树。因此,我想扩展supervisor(引擎

免责声明:我对Erlang和OTP非常陌生

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

我知道gen_事件,但它在单个事件管理器进程中处理事件,而我希望每个订阅者都是一个独立的、自治的进程。此外,我无法浏览gen_事件的处理程序。不幸的是,谷歌搜索结果充满了XMPP(Ejabberd)和RabbitMQ链接,所以我没有找到任何与我的想法相关的内容

我的想法是这样的子模型无缝地映射到监控树。因此,我想扩展supervisor(引擎盖下的一个
gen_服务器
),以便能够向其所有的孩子发送cast消息

我已经在我快速而肮脏的自定义“dispatcher”行为中破解了这一点:

-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}.
-模块(调度程序)。
-延伸(主管)。
-导出([notify/2,start\u link/2,start\u link/3,handle\u cast/2])。
启动链接(模块、参数)->
gen_服务器:启动链接(dispatcher,{self,Mod,Args},[])。
开始链接(SupName、Mod、Args)->
gen_服务器:启动链接(SupName,dispatcher,{SupName,Mod,Args},[])。
通知(调度员、消息)->
genu服务器:cast(Dispatcher,{message,message})。
handle_cast({message,message},State)->
{reply,Children,State}=supervisor:handle_call(哪个_Children,dummy,State),
Pids=lists:filter(fun(Pid)->is_Pid(Pid)结束,
列表:map(fun({u-Id,Child,{u-Type,{u-Modules})->Child-end,
儿童),,

[gen_server:cast(Pid,Message)| Pid从您的代码中,我认为gen_事件处理程序是一个完美的匹配

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

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

通常这些自治进程是gen_服务器,您只需从事件回调调用gen_服务器:cast

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

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

如果您使用
gen\u event:add\u sup\u handler
函数添加流程(如果语义适合您),您甚至可以将事件管理器用作主管

更好地了解gen_事件的在线资源:

除此之外,Erlang的书中都有一些gen_事件的介绍,可能是你在


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

有时候以前,我读到了关于øMQ(ZeroMQ)的文章,它有一系列与不同编程语言的绑定


如果它不是一个纯erlang解决方案,这可能是一个选择。

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

我最近使用它来实现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}).

消息是否已存储,新进程订阅是否获得了它们的全部历史记录。还是消息仅从进程订阅的时间点传递?后者;如Redis或0MQ Pub/Sub。我将再看一看gen_event
,谢谢。这是一个“监督”进程的示例这里可以找到一个
gen_事件处理程序
:事件管理器的一个问题是,每种类型的事件处理程序最多只能有一个,因此,如果要发送给许多相同类型的事件处理程序,则只有一个处理程序会发送给所有类型的事件处理程序。