Erlang:扩展gen_server

4
我希望扩展gen_server(创建gen_server_extra)以实现一些附加功能。要求如下:
  1. gen_server_extra进程应该像常规的gen_server一样运行。例如,它们应该通过gen_server:call接受调用,与SASL集成,适配OTC监督树等。
  2. gen_server_extra进程应当具有由gen_server_extra提供的附加功能。这基本上意味着部分消息将由gen_server_extra代码处理,而不是将它们传递给回调模块。其余消息原封不动地传递给回调模块。
  3. gen_server_extra功能需要其自己的状态,这个状态应该被隐藏起来,不让回调模块看到。
最简单的方法是什么?
2个回答

7

最好、最模块化的方法是在一个模块中实现新行为(如gen_ext_server),并从那里封装gen_server行为。

首先,请确保您的行为与gen_server完全相同:

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

% Exports...

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

实现所有与gen_server相关的回调函数,在状态中保留实现您行为的回调模块的名称:

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

然后,在每个gen_server回调函数中,实现您的行为,如果需要,调用回调模块:

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.

handle_cast/2handle_info/2terminate/1等实现类似的功能。


是的,在思考了一段时间后,我得出了类似的设计。唯一的问题是有很多样板代码。 - Ivan Dubrov
1
OTP中的行为并不是真正可扩展的,这是可以理解的,因为它会影响性能和简单性。 - Adam Lindberg

-1

嗯,我不会把它称为定制化,而是新的行为方式。你需要定义自己的行为。这个教程将带你完成这个过程 可在trapexit.org找到。
然而,需求不是很明确。

将回调函数访问服务器状态的主要特点是编写正常的顺序代码,可以在任何时候和任何地方操作应用程序的状态,而不会干扰并发细节。 否则,如果这是前进的方法,请实现您自己的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接