Best practices for Lwt_main.run

I’m writing a program that will repeatedly spawn processes and use Lwt to asynchronously watch their stdout and wait for them to terminate. As I understand it, these watching tasks should be started with Lwt.async, but I also need to call Lwt_main.run somewhere to run the scheduler. Also, it seems like the task run by Lwt_main.run can’t terminate before the ones I started with Lwt.async (i.e. I can’t just do Lwt_main.run (Lwt_io.printl …) somewhere).

Currently I’m starting the stdout watch task with Lwt.async and the wait for termination with Lwt_main.run. This works, but it doesn’t seem ideal – it means I’ll make multiple (non-nested) calls to Lwt_main.run and produces a brittle structure. Should I be doing something like calling Lwt_main.run on a promise that will never be fulfilled instead?

If you have any code examples it’ll help, but I think I know what you mean. Lwt_main.run should only be called once on the outer level, and you can choose to resolve it or run continuously from within.

So it would be something like this:

let start_watching process =
    let () = Lwt.async (some_function_of process) in
    let () = Lwt.async (another_function_of process) in
    ...

where start_watching is called repeatedly (sequentially). Currently I’m making the last call to Lwt.async in start_watching a call to Lwt_main.run instead (at least, I was at the time of the original post) but that means it gets called each time start_watching is run. I’m not sure if that’s actually an issue since the Lwt calls in each start_watching call shouldn’t overlap, but it doesn’t seem like the best way of doing things.

Rather than call Lwt.main_run again, i’d have a recursive function that’s called. I.e.

let rec main status =
  match status with
  | `Resume -> main `Resume
  | `End -> Lwt.return ()
  | `Error err -> Lwt.fail err

let _ =
  Lwt_main.run (Lwt.catch (fun ()  -> main `Resume) (fun err  -> exit 0))

inside the Resume case you can then do any async stuff you want, and call main(Resume) when you’re ready to iterate again.