Erlang: расширенный gen_server

Я хочу расширить 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 функциональность требует своего собственного состояния, которое должно быть скрыто от модуля обратного вызова.

Как это сделать проще всего?


person Ivan Dubrov    schedule 19.07.2011    source источник


Ответы (2)


Лучшим, наиболее модульным подходом было бы реализовать новое поведение в модуле (например, 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/2, handle_info/2, terminate/1 и т. Д.

person Adam Lindberg    schedule 19.07.2011
comment
Да, немного подумав, я пришел к похожему дизайну. Единственная проблема - это много шаблонного кода. - person Ivan Dubrov; 19.07.2011
comment
Поведение в OTP на самом деле не расширяемо, что понятно, потому что это повлияет на производительность и простоту. - person Adam Lindberg; 19.07.2011

ну, я бы не назвал это настройкой, это скорее новое поведение. Вам нужно определить собственное поведение. Учебное пособие, которое проведет вас через это, находится на trapexit.org. < br> Однако требования не совсем правильные.

Основная суть предоставления доступа функциям обратного вызова к состоянию сервера состоит в том, чтобы написать нормальный последовательный код, управляющий состоянием вашего приложения, когда и где вы хотите, не прерывая детали параллелизма. В противном случае, если это правильный путь, реализуйте свое собственное поведение.

person Muzaaya Joshua    schedule 19.07.2011