2011-07-19 2 views
4

Je souhaite étendre gen_server (créer un gen_server_extra) avec quelques fonctionnalités supplémentaires. Les exigences sont les suivantes:Erlang: extended gen_server

  1. Les processus gen_server_extra devraient se comporter comme un gen_server régulier « s. Par exemple, ils doivent accepter les appels via gen_server:call, intégrer avec SASL, ajustement arbre de surveillance de gré à gré, etc.
  2. processus gen_server_extra devraient avoir une fonctionnalité supplémentaire, fournie par gen_server_extra. Cela signifie que certains des messages seront traités par le code gen_server_extra, sans les transmettre au module de rappel. Le reste des messages est transmis au module de rappel en l'état. La fonctionnalité nécessite son propre état qui doit être caché du module de rappel. Fonctionnalité

Quelle est l'approche la plus simple pour faire cela?

Répondre

7

La meilleure approche, la plus modulaire, consisterait à implémenter un nouveau comportement dans un module (par exemple gen_ext_server) et d'envelopper le comportement gen_server à partir de là.

Tout d'abord, assurez-vous que votre comportement est identique à gen_server:

-module(gen_ext_server). 
-behavior(gen_server). 

% Exports... 

behaviour_info(Type) -> gen_server:behaviour_info(Type). 

Mettre en oeuvre tous les callbacks nécessaires pour gen_server, conserver le nom du module de rappel qui implémente votre comportement dans votre état:

init([Mod|ExtraArgs]) -> 
    % ... 
    ModState = Mod:init(ExtraArgs), 
    #state{mod = Mod, mod_state = ModState, internal = [...]} 

Puis, dans chaque rappel gen_server, implémentez votre comportement, puis appelez le module de rappel si nécessaire:

handle_call(internal, _From, State) -> 
    % Do internal stuff... 
    {reply, ok, State}; 
handle_call(Normal, From, State = #state{mod = Mod, mod_state = ModState}) -> 
    case Mod:handle_call(Normal, From, ModState) of 
     {reply, Reply, NewState} -> 
      {reply, Reply, #state{mod_state = NewState}; 
     ... -> 
      ... 
    end. 

Mettre en oeuvre des fonctionnalités similaires pour handle_cast/2, handle_info/2, terminate/1 etc.

+0

Oui, après quelques réflexions, je suis arrivé à la conception similaire. Le seul problème est beaucoup de code standard. –

+1

Les comportements dans OTP ne sont pas vraiment extensibles, ce qui est compréhensible car cela aurait un impact sur les performances et la simplicité. –

-1

bien, je ne voudrais pas appeler la personnalisation, mais plutôt un nouveau comportement. Vous devez définir votre propre comportement. A tutorial which will take you through this est trouvé à trapexit.org.
Cependant, les exigences ne sont pas très appropriées. L'essentiel de donner l'accès des fonctions de rappel à l'état du serveur est d'écrire du code séquentiel normal manipulant l'état de votre application quand et où vous voulez sans interrompre les détails de la concurrence. Sinon, si c'est le chemin à suivre, implémentez votre propre comportement.