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.
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.