After talking with @ulrikstrid about having an async router, it makes a lot of sense that the default middleware stack works asynchronously.
The first step is fairly straightforward, we just need to parametrize the Middleware stack with an io('a) type. Then the runner of the stack will get passed a sequencing function (>>=). Voila, all middleware is now async.
The interesting bit to me is how to make it flexible enough to allow for middleware that will define how the rest of the stack unfolds.
For example:
server
|> use(Middleware.log)
|> use(Router.with_handler(handler))
|> Lwt_main.run;
This would log before routing, and then return a response. But what would need to happen to allow for log to actually log the response status and response time?
The above right now behaves like:
- Log stuff
- Route and reply
Whereas I'd like the async behavior to allow for:
- Begin Measuring time
- Route and reply
- Log time between 1 and now
Without changing the way the middleware stack was built. In other words, the definition of the Middleware.log middleware would have to look a little more like:
let log = (ctx, next) => {
let time_1 = Time.now();
next() >>= (result => {
let time_2 = Time.now();
Log.debug( m => m("%f.3ms", time_2 -. time_1);
result
});
};