-
Notifications
You must be signed in to change notification settings - Fork 174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lower-level support for long-running cohttp-async connections #704
Lower-level support for long-running cohttp-async connections #704
Conversation
I'm opened this as a PR to give an example of the interface I'm looking for, but I'm open for suggestions if there's a better way to do this. Cohttp_async.Client.callv doesn't work for me because I need arbitrary-length connections (basically trying to keep a connection open until the server closes it), but One piece I'm still trying to figure out is if there's any way to detect that the server has disconnected before sending subsequent requests. The |
253d971
to
62e0d2f
Compare
(I'm also happy to match any style guidelines but I'm not sure what they are for this project) |
In the internal project I'm working on, I'm attempting a request, catching the "Connection closed by remote host" exception and then retrying once: let rec loop ~is_first_request =
Monitor.try_with (fun () ->
let%bind connection =
let key = Scheme_host_port.of_uri target in
match Hashtbl.find t.open_connections key with
| Some connection when not (Cohttp_async.Client.Connection.is_closed connection)
-> return connection
| _ ->
let%bind ssl_config = ssl_config ?hostname:(Uri.host target) () in
let%map connection =
Cohttp_async.Client.Connection.connect ~ssl_config target
in
Hashtbl.set t.open_connections ~key ~data:connection;
connection
in
Cohttp_async.Client.Connection.request ~body connection req)
>>= function
| Ok response -> return response
| Error e ->
(* We have no way of detecting if the remote side closed a connection before we were able to make a request,
so always make a request and retry once if the connection was closed *)
let remote_connection_closed =
match Monitor.extract_exn e with
(* This exception is thrown by Cohttp if the other end hangs up *)
| Failure msg when is_first_request && msg = "Connection closed by remote host" ->
true
(* This exception is thrown if multiple requests are queued when the connection is closed *)
| e when Exn.to_string e |> String.is_substring ~substring:"throttle aborted job"
-> true
| _ -> false
in
if remote_connection_closed
then (
Log.Global.info
"Remote connection to %s was closed, opening a new one"
(Uri.to_string target);
loop ~is_first_request:false)
else (
Log.Global.error "%s" (Exn.to_string e);
Exn.reraisef
e
!"Failed to connect to '%s' with request: %{sexp:Request.t}"
(Uri.to_string uri)
req
())
in
loop ~is_first_request:true |
I currently have code similar to this inlined in my Blue_http client but I would rather upstream this piece if I can since I need pieces of Cohttp_async that aren't publish (Cohttp_async.Client.Net): https://github.com/brendanlong/blue-http/blob/master/src/connection.ml |
Sorry for the delay on this PR. |
@avsm I have never used async, I don't feel in the position to properly review this change. Can you recommend somebody more familiar with it for the review? |
The "connection closed by remote host" exception is throw by Cohttp, so we could replace that with a more explicit (not-Failure) exception if you want to: https://github.com/mirage/ocaml-cohttp/blob/master/cohttp-async/src/client.ml#L53 |
If you want to rebase this on master we can try to have it merged before cohttp-3 is merged, or have it ready for a bugfix chottp 3.1 release at least |
This adds Cohttp_async.Client.Connection which allows you to open a connection and re-use it for multiple requests. Unlike callv, this makes it easy to handle errors and correlate requests and responses.
62e0d2f
to
ce24b30
Compare
Ok I rebased this |
Thanks. Yesterday I spent some time to understand what you were doing. It took a while to wrap my head around async but I believe the patch is sound. Is there any test worth to add? Besides that. Do you still need to catch the "Connection closed by remote host" exception in the same way when using the new cohttp on the master branch? |
In #692 there was this suggestion concerning the issue:
The reason I am asking is that exposing the |
So, I did a deep look into the proposed PR and it seems that the initial error is mostly about the current proposed API of The best for me is to accept the PR as is if @brendanlong really needs it 😕 . |
Thanks for looking into it. I have actually privately heard from other people that would benefit from having this. @brendanlong if you rebase one last time and add an entry in the CHANGES file I am going to merge |
Merging, I need to edit the changes file anyways |
…lwt, cohttp-lwt-unix, cohttp-lwt-unix-ssl, cohttp-top, cohttp-async and cohttp-mirage (3.0.0) CHANGES: - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - port to conduit 3.0.0: minor breaking changes on the server API, an explicit distinction between cohttp-lwt-unix (using tls), cohttp-lwt-notls and cohttp-lwt-ssl (using lwt_ssl), and includes ssl in cohttp-async (@dinosaure mirage/ocaml-cohttp#692) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686)
…lwt, cohttp-lwt-unix, cohttp-lwt-unix-ssl, cohttp-top, cohttp-async and cohttp-mirage (3.0.0) CHANGES: - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - port to conduit 3.0.0: minor breaking changes on the server API, an explicit distinction between cohttp-lwt-unix (using tls), cohttp-lwt-notls and cohttp-lwt-ssl (using lwt_ssl), and includes ssl in cohttp-async (@dinosaure mirage/ocaml-cohttp#692) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686)
…lwt, cohttp-lwt-unix, cohttp-lwt-unix-ssl, cohttp-top, cohttp-async and cohttp-mirage (3.0.0) CHANGES: - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - port to conduit 3.0.0: minor breaking changes on the server API, an explicit distinction between cohttp-lwt-unix (using tls), cohttp-lwt-notls and cohttp-lwt-ssl (using lwt_ssl), and includes ssl in cohttp-async (@dinosaure mirage/ocaml-cohttp#692) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686)
…lwt, cohttp-lwt-unix, cohttp-lwt-unix-ssl, cohttp-top, cohttp-async and cohttp-mirage (3.0.0) CHANGES: - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - port to conduit 3.0.0: minor breaking changes on the server API, an explicit distinction between cohttp-lwt-unix (using tls), cohttp-lwt-notls and cohttp-lwt-ssl (using lwt_ssl), and includes ssl in cohttp-async (@dinosaure mirage/ocaml-cohttp#692) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686)
…ohttp-top, cohttp-async and cohttp-mirage (4.0.0) CHANGES: - cohttp.response: fix malformed status header for custom status codes (@mseri @aalekseyev mirage/ocaml-cohttp#752) - Remove dependency to base (@samoht mirage/ocaml-cohttp#745) - fix opam files and dependencies - add GitHub Actions workflow (@smorimoto mirage/ocaml-cohttp#739) - lwt_jsoo: Forward exceptions to caller when response is null (@mefyl mirage/ocaml-cohttp#738) - Remove wrapped false (@rgrinberg mirage/ocaml-cohttp#734) - Use implicit executable dependency for generate.exe (@TheLortex mirage/ocaml-cohttp#735) - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686) - [reverted] breaking changes to client and server API to use conduit 3.0.0 (@dinosaure mirage/ocaml-cohttp#692). However, as the design discussion did not reach consensus, these changes were reverted to preserve better compatibility with existing cohttp users. (mirage/ocaml-cohttp#741, @samoht)
…ohttp-top, cohttp-async and cohttp-mirage (4.0.0) CHANGES: - cohttp.response: fix malformed status header for custom status codes (@mseri @aalekseyev mirage/ocaml-cohttp#752) - Remove dependency to base (@samoht mirage/ocaml-cohttp#745) - fix opam files and dependencies - add GitHub Actions workflow (@smorimoto mirage/ocaml-cohttp#739) - lwt_jsoo: Forward exceptions to caller when response is null (@mefyl mirage/ocaml-cohttp#738) - Remove wrapped false (@rgrinberg mirage/ocaml-cohttp#734) - Use implicit executable dependency for generate.exe (@TheLortex mirage/ocaml-cohttp#735) - cohttp: update HTTP codes (@emillon mirage/ocaml-cohttp#711) - cohttp: add Uti.t to uri scheme (@brendanlong mirage/ocaml-cohttp#707) - cohttp: fix chunked encoding of empty body (@mefyl mirage/ocaml-cohttp#715) - cohttp-async: fix body not being uploaded with unchunked Async.Pipe (@mefyl mirage/ocaml-cohttp#706) - cohttp-{async, lwt}: fix suprising behaviours of Body.is_empty (@anuragsoni mirage/ocaml-cohttp#714 mirage/ocaml-cohttp#712 mirage/ocaml-cohttp#713) - cohttp-lwt-jsoo: rename Cohttp_lwt_xhr to Cohttp_lwt_jsoo for consistency (@mseri mirage/ocaml-cohttp#717) - refactoring of tests (@mseri mirage/ocaml-cohttp#709, @dinosaure mirage/ocaml-cohttp#692) - update documentation (@dinosaure mirage/ocaml-cohttp#716, @mseri mirage/ocaml-cohttp#720) - cohttp: fix transfer-encoding ordering in headers (@mseri mirage/ocaml-cohttp#721) - lower-level support for long-running cohttp-async connections (@brendanlong mirage/ocaml-cohttp#704) - fix deadlock in logging (@dinosaure mirage/ocaml-cohttp#722) - add of_form and to_form functions to body (@seliopou mirage/ocaml-cohttp#440, @mseri mirage/ocaml-cohttp#723) - cohttp-lwt: partly inline read_response, fix body stream leak (@madroach @dinosaure mirage/ocaml-cohttp#696) - improve media type parsing (@seliopou mirage/ocaml-cohttp#542, @dinosaure mirage/ocaml-cohttp#725) - add comparison functions for Request.t and Response.t via ppx_compare (@msaffer-js @dinosaure mirage/ocaml-cohttp#686) - [reverted] breaking changes to client and server API to use conduit 3.0.0 (@dinosaure mirage/ocaml-cohttp#692). However, as the design discussion did not reach consensus, these changes were reverted to preserve better compatibility with existing cohttp users. (mirage/ocaml-cohttp#741, @samoht)
This adds Cohttp_async.Client.Connection which allows you to open
a connection and re-use it for multiple requests.
Unlike callv, this makes it easy to handle errors and correlate
requests and responses.