(Note in this document, I am very careful about using the name Mojo vs Mojolicious, and also that this only deals with simple HTTP requests).
When a server is instantiated, it subscribes to its own request
event with a callback which calls the app's handler
method (which I shall discuss later).
When the server starts listening, it establishes a stream read
handler.
When that fires, if necessary it builds a transaction which subscribes to its own request method which will then emit a request
event from the server (which we already subscribed to above) and then consumes data/text from the stream.
When the transaction believes that the message is complete it emits a request
event which as we saw is re-emitted from the server thereby firing the app's handler
method.
As defined in the Mojo docs, the handler
method "is the main entry point to your application or framework and will be called for each new transaction".
Sidenote, to implement a new framework on Mojo, all you need to do is inherit from Mojo and implement that method.
Your Mojolicious-based app usually doesn't implement the handler
method; usually it is inherited from the Mojolicious class.
Before that is fired, let's first look at the constructor that Mojolicious implements.
After setting up some defaults, the new
method subscribes to the around_dispatch
hook for exception handling (and does so before you have a chance to subscribe, it wants to be first) and then calls your startup
method.
In this method you establish your application, most notably its routes.
Now back to the handler, Mojo's handler
method is meant to be overloaded and so Mojolicious implements it.
Looking within, you see how the application subscribes to its own around_action
and around_dispatch
hooks on (and only on) the first request.
Note that this time, by doing so on the first request (and thus after the startup method) these are the last subscribers to these hooks.
Moving on, for each request, the application builds a controller for the transaction and emits the around_dispatch
hook (which was just established if this is the first request).
If the request reaches the end of the hook subscribers without setting mojo.rendered
then it logs that nothing has been rendered.
If your startup established an around_dispatch
hook, then it is fired, however the last (and usually only) subscriber is the application's own (as seen above).
When this fires, it calls the app's dispatch
method.
This method emits the before_dispatch
hook, handles static files, then emits the before_routes
hook and lets the router handle most the remaining dispatch.
The router is beyond the scope of this document.
Once the request is routed, there are many ways that the response can be rendered, but mainly the reader should focus on the controller's render
and rendered
methods.
Eventually the data accumulated via routing and rendering is converted back into a message which is written to the stream by telling the transaction to resume which causes a the transaction to emit a resume
event.
Now back when the Server initially emitted the request event, it also established a subscriber for the resume
event.
That callback finally writes the response to the stream.