erlangyawserlangweb

How to handle multiple requests to out(A) in yaws?


Recently, I have startet working on a REST api in erlang & Yaws. I don't understand how yaws & my module handle multiple requests.

I do have api module gathering all requests :

appmods = </, api>

and my test module :

-module(api).
out(_Arg) ->
    io:format("my pid  ~p ~n", [self()]),
    loop(200000000),
    [{status, 200}, {header, {"Vary", "Accept"}},
     {content, "application/json", ""}].

At this point, my understanding is that yaws spawns only one instance of my api module and sends there all the requests. And so, only one request can be handled at any given time.

Is there a way to spawn more processes of api module and spread requests among them?

Or should I do a lot more of appmods for every single type of API request?

Or is my understanding of how does yaws work is fundamently wrong?

Thanks for help.


Solution

  • Internally Yaws keeps a pool of acceptor processes. Requests are handled on those processes. Yaws does not spawn a new process for each appmod and direct all requests for a given appmod to its process. Rather, an acceptor handles a new connection, reads in requests on that connection and dispatches them, and sends responses. Once the connection closes, either due to the client closing it, due to a "Connection: close" HTTP header being present, due to an HTTP 1.0 request (which by default requires closing the connection after each request/response), or due to client inactivity resulting in the server closing it, the acceptor process returns to the pool.

    The JPEG image of your output linked in your comment above that shows the same pid handling all requests is likely due to your client holding the connection open and sending each new request on the same connection, resulting in the same server process handling all those requests. If you instead try a client like Apache Bench (also known as "ab"), which defaults to HTTP 1.0 and thus a new connection for every request, you'll see a different process handling each request.

    Something to be aware of for appmods, by the way, is if you implement them using a state-holding process executing a tail recursive loop, such as a gen_server, all requests for that appmod will indeed be directed to the same pid, which is the pid of the looping process. In other words, the request will be handled initially in a Yaws acceptor process as described earlier, but it will then cross over into the gen_server process once the appmod calls into it. This serialization of requests onto a single process has nothing to do with Yaws but rather with how the appmod is implemented — you might want to read one of my published articles about this for more details. In short, don't write appmods that way unless such request serialization is acceptable for your application.