Skip to content

Fetch status from either headers or trailers #5

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

Merged
merged 4 commits into from
Apr 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 23 additions & 22 deletions lib/grpc-async/client.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,6 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
let read_body_ivar = Ivar.create () in
let handler_res_ivar = Ivar.create () in
let out_ivar = Ivar.create () in
let response_handler (response : H2.Response.t) (body : [ `read ] H2.Body.t) =
Ivar.fill read_body_ivar body;
don't_wait_for
(match response.status with
| `OK ->
let%bind handler_res = Ivar.read handler_res_ivar in
Ivar.fill out_ivar (Ok handler_res);
return ()
| _ ->
Ivar.fill out_ivar (Error (Grpc.Status.v Grpc.Status.Unknown));
return ())
in
let trailers_status_ivar = Ivar.create () in
let trailers_handler headers =
let code =
Expand All @@ -49,10 +37,26 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
in
match code with
| None -> ()
| Some code ->
let message = H2.Headers.get headers "grpc-message" in
let status = Grpc.Status.v ?message code in
Ivar.fill trailers_status_ivar status
| Some code ->
match Ivar.is_empty trailers_status_ivar with
| true ->
let message = H2.Headers.get headers "grpc-message" in
let status = Grpc.Status.v ?message code in
Ivar.fill trailers_status_ivar status
| _ -> (* This should never happen, but just in case. *) ()
in
let response_handler (response : H2.Response.t) (body : [ `read ] H2.Body.t) =
Ivar.fill read_body_ivar body;
don't_wait_for
(match response.status with
| `OK ->
let%bind handler_res = Ivar.read handler_res_ivar in
Ivar.fill out_ivar (Ok handler_res);
return ()
| _ ->
Ivar.fill out_ivar (Error (Grpc.Status.v Grpc.Status.Unknown));
return ());
don't_wait_for (return (trailers_handler response.headers))
in
let write_body : [ `write ] H2.Body.t =
do_request ?trailers_handler:(Some trailers_handler) request
Expand All @@ -64,13 +68,10 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
return ());
let%bind out = Ivar.read out_ivar in
let%bind trailers_status =
(* trailers_status_ivar is not always filled at this point, because
* trailers_handler is not always called. Perhaps because there are no
* trailers in some cases? For one example, it happens in lnd when
* QueryRoutes returns an empty list. In this case, we let the call return
* with an unknown status. *)
(* In case no grpc-status appears in headers or trailers. *)
if Ivar.is_full trailers_status_ivar then Ivar.read trailers_status_ivar
else return (Grpc.Status.v Grpc.Status.Unknown)
else return (
Grpc.Status.v ~message:"Server did not return grpc-status" Grpc.Status.Unknown)
in
match out with
| Error _ as e -> return e
Expand Down
40 changes: 25 additions & 15 deletions lib/grpc-lwt/client.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,6 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
let read_body, read_body_notify = Lwt.wait () in
let handler_res, handler_res_notify = Lwt.wait () in
let out, out_notify = Lwt.wait () in
let response_handler (response : H2.Response.t) body =
Lwt.wakeup_later read_body_notify body;
Lwt.async (fun () ->
if response.status <> `OK then (
Lwt.wakeup_later out_notify
(Error (Grpc.Status.v Grpc.Status.Unknown));
Lwt.return_unit)
else
let+ handler_res in
Lwt.wakeup_later out_notify (Ok handler_res))
in
let status, status_notify = Lwt.wait () in
let trailers_handler headers =
let code =
Expand All @@ -48,9 +37,24 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
match code with
| None -> ()
| Some code ->
let message = H2.Headers.get headers "grpc-message" in
let status = Grpc.Status.v ?message code in
Lwt.wakeup_later status_notify status
match Lwt.state status with
| Sleep ->
let message = H2.Headers.get headers "grpc-message" in
let status = Grpc.Status.v ?message code in
Lwt.wakeup_later status_notify status
| _ -> (* This should never happen, but just in case. *) ()
in
let response_handler (response : H2.Response.t) body =
Lwt.wakeup_later read_body_notify body;
Lwt.async (fun () ->
if response.status <> `OK then (
Lwt.wakeup_later out_notify
(Error (Grpc.Status.v Grpc.Status.Unknown));
Lwt.return_unit)
else
let+ handler_res in
Lwt.wakeup_later out_notify (Ok handler_res));
Lwt.async(fun () -> Lwt.return (trailers_handler response.headers))
in
let write_body =
do_request ?trailers_handler:(Some trailers_handler) request
Expand All @@ -60,7 +64,13 @@ let call ~service ~rpc ?(scheme = "https") ~handler ~do_request
let+ handler_res = handler write_body read_body in
Lwt.wakeup_later handler_res_notify handler_res);
let* out in
let+ status in
let+ status =
match Lwt.is_sleeping status with
(* In case no grpc-status appears in headers or trailers. *)
| false -> status
| true -> Lwt.return (
Grpc.Status.v ~message:"Server did not return grpc-status" Grpc.Status.Unknown)
in
match out with Error _ as e -> e | Ok out -> Ok (out, status)

module Rpc = struct
Expand Down