I don’t think that this is exactly your code. For one thing it doesn’t type because Lwt_main.run
expects a promise. But more importantly, this will not do any work in the tasks that’s beyond I/O or pauses/yield. E.g., consider the code below
let () =
Lwt_main.run @@
let open Lwt.Syntax in
ignore (let* () = Lwt_unix.sleep 5. in print_endline "waited 5"; Lwt.return ());
ignore (let* () = Lwt_unix.sleep 7. in print_endline "waited 7"; Lwt.return ());
Lwt.return ()
The executable exits immediately, no printing happens.
That’s because Lwt_main.run
simply “awaits” for the given promise to resolve at which point it returns the value into the OCaml world and the execution of the program continues as normal (i.e., as a non-Lwt program would).
If there are pending I/O jobs and unresolved promises in the scheduler then they are simply ignored.
For a server, you can pass your main-loop to run
(in the case of a server, the loop that calls accepts, spawns a task and then calls accept again, indefinitely). Or sometimes you can just pass a never-resolving promise (fst (Lwt.task ())
or similar).
Regarding exception management, I’d recommend that you use Lwt.dont_wait
rather than on_failure
+ignore
. It should be roughly equivalent but it will force you to have a unit
promise and to wrap your promise inside a lambda which avoids exceptions leaking out.
E.g., the following will raise “outside of the promise” and the handler won’t be called
let p =
if param < 0 then raise (Invalid_argument "");
let* …
in
Lwt.on_failure p (fun exn -> …);
ignore p;
whereas the same code with dont_wait
will pass the exception to the handler.