9
votes

Erlang: Pubsub simple pour les processus - Mon approche est-elle correcte?

Disclaimer: Je suis assez nouveau à Erlang et OTP.

Je veux un simple pubsub à Erlang / OTP, où les processus pourraient souscrire à un "moyeu" et recevoir une copie de messages envoyés à ce hub. p>

Je sais sur gen_event code>, mais il traite des événements dans un seul processus de gestionnaire d'événements, alors que je souhaite que chaque abonné soit un processus distinct et autonome. En outre, j'ai été incapable de grok Gen_Event CODE> SUPERLERS DE MANUTLERS. Malheureusement, les résultats de Google étaient pleins de liens XMPP (Ejabberd) et de rabbbitmq, donc je n'ai rien trouvé de pertinent à mon idée. P>

Mon idée est que ce modèle pubsub est parfaitement transparente dans l'arbre de supervision. J'ai donc pensé étendre le superviseur (un gen_server code> sous la hotte) pour pouvoir envoyer un message de distribution à tous ses enfants. P>

J'ai piraté cela dans mon rapide Comportement "Dispatcher" personnalisé sale: P>

-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}.


2 commentaires

Les messages sont-ils stockés et que de nouveaux processus se souscrivent à l'historique total. Ou est-ce que les messages ne sont transmis que du moment où un processus souscrit?


Le dernier; comme dans Redis ou 0 mq pub / sous. Je vais prendre un autre regard sur gen_event , merci.


4 Réponses :


10
votes

de votre code, il me semble que les gestionnaires Gen_Event sont une correspondance parfaite.

Les rappels de gestionnaire sont appelés à partir d'un processus central expédiant les messages, mais ces rappels ne devraient pas faire beaucoup de travail.

Donc, si vous avez besoin d'un processus autonome avec son propre état pour les abonnés, envoyez simplement un message dans le rappel d'événement.

Généralement, ces processus autonomes seraient GEN_SERVERS et vous appelleriez simplement Gen_Server: jeté de vos rappels événementiels.

Supervision est un problème distinct, qui peut être géré par l'infrastructure de supervision habituelle fournie avec OTP. La façon dont vous voulez faire une supervision dépend de la sémantique de vos processus d'abonnés. S'ils sont tous des serveurs identiques, vous pouvez utiliser un simple_one_for_one par exemple.

Dans le rappel init des processus d'abonné, vous pouvez mettre le gen_event: add_handler les appels qui les ajoute au gestionnaire d'événements.

Vous pouvez même utiliser le gestionnaire d'événements comme superviseur si vous utilisez le gen_event: add_sup_handler fonction pour ajouter vos processus si la sémantique de ce costume vous convient.

Ressources en ligne pour la compréhension de Gen_Event Meilleur: Décrochez un chapitre Erlang

Sinon, les livres Erlang ont tous une introduction Gen_Event. Probablement la plus complète que vous puissiez trouver dans Erlang et OTP en action

OH et BTW: Je ne voudrais pas pirater vos propres superviseurs pour cela.


2 commentaires

Un exemple de processus "supervise" A Gen_Event Handler peut être trouvé ici: Trapexit. org / gen_tevent_behavior_demystifié


Un problème avec les gestionnaires d'événements est qu'ils ne peuvent avoir qu'au plus un de chaque type de gestionnaire d'événements, donc si vous envoyez à nombre de types de même type, ce sera un gestionnaire qui leur envoie tous.



-2
votes

Il y a parfois, j'ai lu environ Ømq (Zeromq), qui a un tas de liaisons à différentes langages de programmation.

http://www.zeromq.org/

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

S'il ne doit pas une solution pure erlang, cela pourrait être un choix.


0 commentaires

1
votes

Un exemple très simple où vous faites tout ce que vous faites vous-même est dans mon chat_demo qui est un simple Serveur de discussion Web basé sur le Web. Regardez chat_backend.erl (ou chat_backend.lfe si vous aimez les parenthèses) qui permet aux utilisateurs de abonner et ils seront ensuite envoyés tous les messages arriver au backend. Il ne s'intègre pas dans les arbres de supervision, bien que la modification soit simple (bien qu'il utilise proc_lib pour obtenir de meilleurs messages d'erreur).


0 commentaires

11
votes

J'ai récemment utilisé GPROC pour implémenter pubsub. L'exemple du Readme fait l'affaire.

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}).


0 commentaires