Search code examples
erlangerlang-otpgen-serverdev-to-production

How can i change the callback module of a gen_server in erlang? (gen_server:swap_handler)


I am building an app which can run in two modes. A sandbox mode and a production one.

In sandbox mode, i want to make many checks in my gen_server against the database : if table doesn't exist then create it ; if column doesn't exist then add it ; if column type doesn't allow the value i want to store then change it, etc.

In production mode, if a tables does not exist or a column does not match the type of the value, it will fail and that is ok.

So, in order to avoid cumbersome code like "case State#state.is_sandbox of true -> ... ", i would like to have two different modules for my gen_server, and i would like to change the current module either in handle_call or handle_info.

Actually, i just want to go from sandbox to production, but i think if it works this way, it could work backwards.

Thanks.


Solution

  • You can add module, which is a name of a module, to the state in gen_server. Then you will need 2 modules - sandbox and production that both implement the same functions (you could create a behaviour for it).

    The gen_server callbacks will call module:function which will be a function either from sandbox or production module. The module can be set in init function of the gen_server, to change it, simply add a new function(s) to the gen_server:

    use_production() ->
        gen_server:cast(production).
    
    ....
    
    handle_cast(production, State) ->
        {noreply, State#state{module = production}).
    

    The same for the sandbox module.

    An example of a gen_server's callback with the module:

    handle_call(Msg, _From, #state{module = Module} = State) ->
        Module:function(Msq),
        {reply, ok, State}.
    

    The function must be implemented in both sandbox and production modules.