Как отправить несколько TCP-сообщений и продолжить, если одно из них успешно - PullRequest
1 голос
/ 08 октября 2019

В настоящее время я пишу некоторый сетевой код, и мне нужно отправить большое количество сообщений, а затем дождаться одного ответа.

Учитывая, что у меня есть функция, которая возвращает входные и выходные каналы дляу меня есть сокет:

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

Насколько я понимаю, выбор должен отменять все текущие запросы после того, как он выполнит обещание в resps. Проблема заключается в том, что если какое-либо из этих соединений не удается / отказывается, возникает исключение Unix.ECONNREFUSED.

Мой вопрос: какова правильная семантика, чтобы заставить Lwt.pick игнорировать исключения?

Опции, о которых я до сих пор думал, заключаются в том, чтобы отследить исключительность в запросах:

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

Но я не уверен, при каких условиях Lwt.pick будет просматривать эти обещания, отклоненные?

Обновление: теперь я обрабатываю ошибки с помощью отменяемых, невыполняемых обещаний:

fst @@ Lwt.task ()

Это кажется хакерским, но, похоже, работает до сих пор.

1 Ответ

2 голосов
/ 08 октября 2019

Обрабатывать исключение явно правильно. Обещания Lwt отклоняются, когда вы отклоняете их явно (используя Lwt.fail) или когда Lwt перехватывает исключение в обратном вызове, который должен был вернуть обещание (например, то, которое вы передали бы Lwt.bind).

Однако для обработки исключений в коде, который вызывает Lwt, вы должны использовать try%lwt вместо простого try.

...