2011-08-30 13 views
7

免責事項:私はErlangとOTPにはかなり新しいです。Erlang:プロセス用の単純なpubsub - 私のアプローチは大丈夫ですか?

Erlang/OTPでは、プロセスがいくつかの「ハブ」に加入し、そのハブに送信されたメッセージのコピーを受け取ることができる単純なpubsubが必要です。

私は約gen_eventを知っていますが、1つのイベントマネージャプロセスでイベントを処理しますが、すべての加入者を独立した独立したプロセスにしたいと考えています。また、私は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ハンドラは完全に一致しているように見えます。

ハンドラのコールバックは、メッセージをディスパッチする1つの中央プロセスから呼び出されますが、これらのコールバックはあまり効果的ではありません。

したがって、サブスクライバのために独自の状態で自律プロセスが必要な場合は、イベントコールバックでメッセージを送信してください。

通常、これらの自律プロセスはgen_serversであり、イベントコールバックからgen_server:castを呼び出すだけです。

監督は別の問題で、OTPに付属の通常の監視インフラストラクチャで処理できます。どのように監督をしたいかは、加入者プロセスのセマンティクスによって決まります。すべてが同じサーバーの場合は、たとえばsimple_one_for_oneを使用できます。

サブスクライバプロセスのコールバックでは、gen_event:add_handlerコールをイベントマネージャに追加することができます。

gen_event:add_sup_handler関数を使用してプロセスを追加する場合は、イベントマネージャをスーパバイザとして使用することもできます。より良いgen_eventを理解するための

オンラインリソース:Learn you some Erlang chapter

そうでない場合はErlangの本すべては、いくつかのgen_event紹介しています。あなたが見つけることができる最も徹底的なものでしょうErlang and OTP in Action

ああ、BTW:私はあなた自身の上司をハックしません。

+1

'gen_event'ハンドラを「監督する」プロセスの例は、ここにあります:http://www.trapexit.org/Gen_event_behavior_demystified – legoscia

+0

うーん、私はダウンダウン者が気に入らなかったことに興味があります。 –

+2

イベントマネージャーの問題は、各タイプのイベントハンドラーのうちの1つのみを持つことができることです。つまり、同じタイプの多くに送信する場合は、それらをすべて送信するハンドラーになります。 – rvirding

-2

時には、私はøMQ(ZeroMQ)について読んでいます。これは、さまざまなプログラミング言語に束縛されています。

http://www.zeromq.org/

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

それは純粋なErlangのソリューションではありませんしなければならない場合、これは選択肢である可能性があります。

1

非常に簡単な例では、自分ですべてを行うのは私の非常に基本的なchat_demoです。これは簡単なWebベースのチャットサーバーです。 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}). 
関連する問題