1

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.

4

1 回答 1

2

明确处理异常是正确的。当您明确拒绝 Lwt 承诺时(使用Lwt.fail),或者当 Lwt 在本应返回承诺的回调中捕获异常时(如您将传递给的承诺), Lwt 承诺将被拒绝Lwt.bind

但是,为了处理调用 Lwt 的代码中的异常,您必须使用try%lwt普通的try.

于 2019-10-08T13:14:21.243 回答