2011-08-30 5 views
7

면책 조항 : 저는 Erlang과 OTP를 처음 보았습니다.Erlang : 프로세스 용 간단한 pubsub - 내 접근 방식은 괜찮습니까?

Erlang/OTP에서는 프로세스가 일부 "허브"에 가입하고 해당 허브로 전송 된 메시지의 사본을받을 수있는 간단한 pubsub가 필요합니다.

저는 약 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}. 

그러나, 모든 것이 첫 눈에 잘 작동하는 것 같다 동안 (아이 메시지를 수신하고 원활하게 때 다시 시작 그들은 실패한다), 이것이 좋은 아이디어 일 때마다 나는 궁금하다.

내 접근 방식을 비판하거나 승인하거나 다른 대안을 권유 할 수 있습니까?

+0

메시지를 저장하고 새 프로세스를 구독하는 경우 해당 메시지의 전체 내역을 가져옵니다. 아니면 메시지가 프로세스가 가입 한 시점에서만 전달되는 것입니까? –

+0

후자; Redis 또는 0MQ Pub/Sub와 같습니다. 덕분에'gen_event'에 대해 다시 한번 살펴 보겠습니다. – drdaeman

답변

9

코드에서 gen_event 핸들러가 완벽하게 일치하는 것으로 보입니다.

처리기 콜백은 메시지를 전달하는 하나의 중앙 처리 프로세스에서 호출되지만 이러한 콜백은 많은 작업을 수행하지 않아야합니다.

가입자에게 자체 상태가있는 자율 프로세스가 필요하면 이벤트 콜백에서 메시지를 보내면됩니다.

일반적으로 이러한 자율 프로세스는 gen_servers가되며 사용자는 이벤트 콜백에서 gen_server : cast를 호출하면됩니다.

감독은 별도의 문제이며 OTP와 함께 제공되는 일반적인 감독 인프라에서 처리 할 수 ​​있습니다. 감독을 원하는 방식은 구독자 프로세스의 의미에 따라 다릅니다. 모두 동일한 서버 인 경우 예를 들어 simple_one_for_one을 사용할 수 있습니다.

구독자 프로세스의 init 콜백에서 이벤트 관리자에 추가하는 호출을 gen_event:add_handler에 넣을 수 있습니다.

gen_event:add_sup_handler 함수를 사용하면 해당 의미론이 사용자에게 적합 할 경우 프로세스를 추가하는 경우에도 관리자로 이벤트 관리자를 사용할 수 있습니다.

Learn you some Erlang chapter은 그렇지 얼랑 책 모든 일부 gen_event 도입을 가지고 이해

온라인 자원은 더 나은 gen_event. 아마도 당신이 찾을 수있는 가장 철저한 사람 일 겁니다. Erlang and OTP in Action

아, 그리고 BTW : 나는 이것을 위해 당신의 수퍼바이저를 해킹하지 않을 것입니다.

+1

'gen_event' 핸들러를 "감독"하는 프로세스의 예는 다음에서 찾을 수 있습니다 : http://www.trapexit.org/Gen_event_behavior_demystified – legoscia

+0

흠 .. 나는 downvoter가 싫어했던 것이 흥미로울 것입니다. –

+2

이벤트 관리자의 문제점은 이벤트 처리기의 각 유형 중 하나만 가질 수 있다는 것입니다. 따라서 많은 수의 동일한 유형으로 보내는 경우 모두에게 보내는 하나의 처리기가됩니다. – rvirding

1

아주 간단한 예제는 간단한 웹 기반 채팅 서버 인 내 chat_demo 인 매우 기본적인 것입니다. chat_backend.erl (또는 괄호가 있으면 chat_backend.lfe)을 보시고 사용자는 을 구독하고을 구독하면 백엔드에 도착하는 모든 메시지가 전송됩니다. 수정이 간단하지만 (더 나은 오류 메시지를 얻기 위해 proc_lib을 사용하더라도) 감독 트리에 맞지 않습니다.

11

최근에 pubsub을 구현하기 위해 gproc을 사용했습니다. 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}). 
관련 문제