erlangstateerlang-otpmochiwebgen-server

Is there any State variable in Mochiweb?


I have skimmed through the Mochiweb code, but have not found any sign of the State variable.

Does something similar to gen_server's State variable exist in Mochiweb?

I need to store some small amount of state-related server-side (not session-related) data on the server and I do not want to use ETS or Mnesia for that.


Solution

  • I think you have somewhat a misunderstanding of what gen_server state is.

    First, let me explain briefly how mochiweb works.

    Mochiweb doesn't produce a gen_server process per client. Instead, it just spawns a new process using proc_lib:spawn/3 and creates a parametrized module, which is, basically, a tuple of the following kind:

    {mochiweb_request, #Port<0.623>, get, "/users", {1, 1}, []}
    

    which is

    {mochiweb_request, Socket, Method, RawPath, HTTPVersion, Headers}
    

    This tuple is used as an argument to a function that you pass as a loop parameter to mochiweb_http:start/1. So, when this "loop" function is called, it will look like this:

    handle_request(Req) ->
        %% The pattern matching below just shows what Req really is
        {mochiweb_request, _, _, _, _, _} = Req,
        ...
    

    Now, to explanation of gen_server state.

    Basically, gen_server is a process with approximately the following structure. Of course, IRL it's more complicated, but this should give you the general idea:

    init(Options)
        State = ...
        loop(Module, State).
    
    loop(Module, State)
        NewState = receive
            {call, Msg, From} -> Module:handle_call(Msg, From, State)
            {cast, Msg} -> Module:handle_cast(Msg, State)
            Info -> Module:handle_info(Info, State)
        end,
        loop(Module, NewState).
    

    So, state is just an argument that you drag through all the function calls and change inside your loop. It doesn't actually matter if your process is a gen_server or not, it doesn't have what lifetime it has. In the following example the term [1, 2, 3] is a state too:

    a() ->
        b([1, 2, 3], now()).
    
    b(State, Timestamp) ->
        Result = do_something(Timestamp)
        c(State, Result).
    
    c(State, Payload) ->
        exit({State, Payload}).
    

    Now, back to mochiweb.

    If you need to create a state of your own, you can just add an extra function argument:

    handle_request(Req) ->
        User = Req:get(path),
        UserData = load_user_data(User),
        handle_request(Req, UserData).
    
    handle_request(Req, UserData) ->
        ...
    

    Now UserData is a state too. You can loop this process, or let it respond and end right away – but you won't lose UserData as long as you pass it as an argument.

    Finally, if you really want to make this process a gen_server (which is really unreasonable in most cases), you can use gen_server:enter_loop/3 function that will make your current process a gen_server. And The 3rd argument of this function will be your state that will be stored inside the started gen_server.