2

I'm developing a web service in Ocaml on top of MirageOS(Unix) and at the moment I'm having some trouble with Lwt.async(). The Lwt documentation states the following:

val async : (unit -> 'a t) -> unit

async f starts a thread without waiting for the result. If it fails (now or later), the exception is given to Lwt.​async_exception_hook.

You should use this function if you want to start a thread that might fail and don't care what its return value is, nor when it terminates (for instance, because it is looping).

So I immediately considered Lwt.async as a good candidate to run some tests and check that actually the execution is asynchronous. Unfortunately it's not working as expected. My code is the following:

let http_callback conn_id req _body =
  Lwt.return(Uri.path (Cohttp.Request.uri req))
  >>= function
     | "/tester" -> Cohttp_lwt_body.to_string _body >>= fun res -> 
        log_lwt ~inject:(fun f -> f "Testing") >>= fun () ->
        Lwt.async(fun () -> TEST.start 100 res !listOfIP);
        H.respond_string ~status:`OK ~body:("DONE") ()
  in
     let spec = H.make ~callback:http_callback () in
     CON.listen conduit (`TCP 8080) (H.listen spec)

For the sake of clarity, TEST.start executes a series of threaded operations. I assume that it doesn't really matter what the function inside Lwt.async is doing, considering that whatever returns/does should be ignored. Am I wrong?

In the end, my question is: why actually the client has to wait for the thread to receive the OK response? With or without async the behaviour is basically the same.

Vittorio Cozzolino
  • 931
  • 1
  • 14
  • 31

1 Answers1

2

Control will only switch back to the HTTP handler if the async thread blocks waiting for something. If it just uses the CPU 100% until it's done then the async thread will probably run to completion first. Try putting a sleep in the tests to check.

Thomas Leonard
  • 7,068
  • 2
  • 36
  • 40
  • Thanks for the answer, will give it a try asap. – Vittorio Cozzolino Dec 05 '16 at 19:31
  • I've substituted completely the piece of code called by TEST.start with Lwt.return(Unix.sleep 10) but the result is exactly the same. When I run curl -X POST --data something http://10.0.0.2:8080/tester the console hangs and I have to wait for 10 seconds to get the reply. I mean if I call sleep from a secondary thread I really don't expect the main thread to stop.. – Vittorio Cozzolino Dec 06 '16 at 12:32
  • 2
    Lwt threads are not preemptive. They are actually promises. Try using `Lwt_unix.sleep 10.` instead of `Lwt.return (Unix.sleep 10)`. – antron Dec 06 '16 at 12:38
  • Thanks, it works now! Now I need to figure out if there is a way of fixing this without a `sleep`. – Vittorio Cozzolino Dec 06 '16 at 13:10
  • 2
    You have passed a function to `async` that is resolving an Lwt promise (wrongly called *thread* by Lwt). This function is running, together with the rest of your Lwt promise resolvers, in a single system thread, in a single OCaml process. So, you need to avoid calling anything blocking from `Unix.` or other modules anywhere in your program, and use the Lwt replacements for everything. Those use system worker threads in the background (if needed) to resolve the various Lwt promises in your main system thread. You probably already saw [`Lwt_unix`](http://ocsigen.org/lwt/dev/api/Lwt_unix). – antron Dec 06 '16 at 14:10