Timeout Cohttprequests

Not sure if this is better suited for StackOverflow or this site, but thought I’d post here to start with.

I see on the server-side of things there’s https://github.com/mirage/ocaml-cohttp/blob/e9c29aec81a1850bc1574684d27ea2ffa6609264/cohttp-lwt-unix/src/server.mli#L13 - but I also see a TODO item to test it.

But for the client side, I’m looking for a way with Cohhtp.Client to make sure a network request doesn’t take longer than n milliseconds.

You can use Lwt.pick or Lwt_unix.with_timeout for this. An example using Lwt.pick:

let get_or_timeout ?(max_request_duration = max_float) uri =
  let open Lwt.Infix in
  let timeout =
    Lwt_unix.sleep max_request_duration >>= fun () ->
    Lwt.return_error `Timed_out
  in
  let get =
    Cohttp_lwt_unix.Client.get uri >>= fun response ->
    Lwt.return_ok response
  in
  Lwt.pick [
    timeout;
    get;
  ]

with type

val get_or_timeout : (Cohttp.Response.t * Cohttp_lwt_body.t, [> `Timed_out ]) result

If the timeout promise finishes first the get promise will be canceled. If the get promise finishes first then the timeout promise will be canceled.

Here’s the version of Async:

let timeout_send2 url timeout =
  let aux url timeout =  
    let uri = Uri.of_string url in
    let%bind _, body = Cohttp_async.Client.get ~interrupt:(after (sec timeout)) uri in
    Body.to_string body    
  in
  Clock.with_timeout (sec timeout) (aux url timeout)
  >>| function
  | `Result body -> Log.debug logger "body: %s" body
  | `Timeout  -> Log.debug logger "Timeout with url:%s" url