2011-08-30 10 views
7

Descargo de responsabilidad: Soy bastante nuevo en Erlang y OTP.Erlang: pubsub simple para procesos: ¿está bien mi enfoque?

Quiero un pubsub simple en Erlang/OTP, donde los procesos pueden suscribirse en algún "concentrador" y recibir una copia de los mensajes que se enviaron a ese concentrador.

Conozco gen_event, pero procesa eventos en un solo proceso de administrador de eventos, mientras que quiero que cada suscriptor sea un proceso independiente y autónomo. Además, no pude asimilar la supervisión de los controladores de gen_event. Lamentablemente, los resultados de Google estaban llenos de enlaces XMPP (Ejabberd) y RabbitMQ, por lo que no encontré nada relevante para mi idea.

Mi idea es que el modelo de pubsub se corresponda perfectamente con el árbol de supervisión. Así que pensé en extender el supervisor (un gen_server debajo del capó) para poder enviar un mensaje de reparto a todos sus hijos.

He hackeado esto en mi costumbre comportamiento "despachador" rápido y sucio-:

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

Sin embargo, mientras todo parece funcionar bien en la primera vista (los niños reciben mensajes y se reinician cuando la perfección fallan), me pregunto siempre que fue una buena idea.

¿Alguien podría, por favor, criticar (o aprobar) mi enfoque, y/o recomendar algunas alternativas?

+0

Son los mensajes almacenados y los nuevos procesos que se suscriben obtienen todo el historial de ellos. ¿O es que los mensajes se transmiten solo desde el momento en que se suscribe un proceso? –

+0

Este último; como en Redis o 0MQ Pub/Sub. Echaré un vistazo a 'gen_event', gracias. – drdaeman

Respuesta

9

Desde su código, me parece que los controladores gen_event son una combinación perfecta.

Las devoluciones de llamada del manejador se llaman desde un proceso central que envía los mensajes, pero estas devoluciones de llamada no deberían hacer mucho trabajo.

Así que si necesita un proceso autónomo con su propio estado para los suscriptores, simplemente envíe un mensaje en la devolución de llamada del evento.

Por lo general, estos procesos autónomos serían gen_servers y usted simplemente llamaría gen_server: cast desde las devoluciones de llamada de su evento.

La supervisión es un problema separado, que puede ser manejado por la infraestructura de supervisión habitual que viene con OTP. La forma en que desee hacer la supervisión depende de la semántica de sus procesos de suscriptor. Si todos son servidores idénticos, podría usar un simple_one_for_one por ejemplo.

En la devolución de llamada init de los procesos del suscriptor puede poner las llamadas gen_event:add_handler que las agrega al administrador de eventos.

Incluso puede usar el administrador de eventos como supervisor si usa la función gen_event:add_sup_handler para agregar sus procesos si la semántica de esto le conviene.

Recursos en línea para comprender mejor gen_event: Learn you some Erlang chapter

De lo contrario los libros Erlang todos tienen alguna introducción gen_event. Probablemente el más exhaustivo que pueda encontrar en Erlang and OTP in Action

Ah, y BTW: No hackearía a sus propios supervisores para esto.

+1

Un ejemplo de un proceso que "supervisa" un controlador 'gen_event' se puede encontrar aquí: http://www.trapexit.org/Gen_event_behavior_demystified – legoscia

+0

Hmm Me interesaría lo que no le gustaba al infractor. –

+2

Un problema con los administradores de eventos es que solo pueden tener como máximo uno de cada tipo de controlador de eventos, por lo que si está enviando a muchos del mismo tipo, habrá un controlador que los envíe a todos. – rvirding

1

Un ejemplo muy simple en el que lo haces todo tú mismo es en mi muy básico chat_demo que es un simple servidor de chat basado en web. Mire chat_backend.erl (o chat_backend.lfe si le gusta paréntesis) que permite a los usuarios suscribirse y luego se les enviarán todos los mensajes que lleguen al back-end. No encaja en árboles de supervisión aunque la modificación es simple (aunque usa proc_lib para obtener mejores mensajes de error).

11

Recientemente he usado gproc para implementar pubsub. El ejemplo del archivo Léame es el truco.

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