I'm writing some networking code currently and I need to send out a large number of messages and then wait for a single response.
Given that I have a function that returns the input and output channels for a socket I have:
let resps = List.map uris ~f:(fun uri ->
let%lwt (ic,oc) = connect uri in
let%lwt () = Lwt_io.write_value oc msg in
Lwt_io.read_value ic
) in
Lwt.pick resps
My understanding of this is that pick should cancel any ongoing requests after it has a fulfilled promise in resps
. The issue is that if any of those connections fails/is refused, an exception is raised Unix.ECONNREFUSED
.
My question is what is the correct semantics to force Lwt.pick
to ignore the exceptions?
Options I've thought of so far are to catch the exception explicity in the requests:
let resps = List.map uris ~f:(fun uri ->
try
let%lwt (ic,oc) = connect uri in
let%lwt () = Lwt_io.write_value oc msg in
Lwt_io.read_value ic
with Unix_error (e,_,_) -> ...
) in
Lwt.pick resps
But I'm not sure under what conditions the Lwt.pick
will view those promises are rejected?
Update: I'm now handling the errors with cancellable, unfulfillable promises:
fst @@ Lwt.task ()
This feels hacky but seems to work so far.