Resto: automatically retry a few times on 502 gateway errors
This commit is contained in:
parent
d6fac868ee
commit
a0b94cff2b
68
vendors/ocplib-resto/lib_resto-cohttp/client.ml
vendored
68
vendors/ocplib-resto/lib_resto-cohttp/client.ml
vendored
@ -95,7 +95,7 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
let faked_media = {
|
let faked_media = {
|
||||||
Media_type.name = AnyMedia ;
|
Media_type.name = AnyMedia ;
|
||||||
q = None ;
|
q = None ;
|
||||||
pp = (fun _enc ppf s -> Format.pp_print_string ppf s) ;
|
pp = (fun _enc ppf s -> Format.fprintf ppf "@[<h 0>%a@]" Format.pp_print_text s) ;
|
||||||
construct = (fun _ -> assert false) ;
|
construct = (fun _ -> assert false) ;
|
||||||
destruct = (fun _ -> assert false) ;
|
destruct = (fun _ -> assert false) ;
|
||||||
}
|
}
|
||||||
@ -136,8 +136,13 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
| `Stream s -> `Stream (Lwt_stream.clone s)
|
| `Stream s -> `Stream (Lwt_stream.clone s)
|
||||||
| x -> x
|
| x -> x
|
||||||
|
|
||||||
let generic_call meth ?(logger = null_logger) ?(headers = []) ?accept ?body ?media uri : (content, content) generic_rest_result Lwt.t =
|
type log = {
|
||||||
let module Logger = (val logger) in
|
log:
|
||||||
|
'a. ?media:Media_type.t -> 'a Encoding.t -> Cohttp.Code.status_code ->
|
||||||
|
string Lwt.t Lazy.t -> unit Lwt.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
let internal_call meth (log : log) ?(headers = []) ?accept ?body ?media uri : (content, content) generic_rest_result Lwt.t =
|
||||||
let headers = List.fold_left (fun headers (header, value) ->
|
let headers = List.fold_left (fun headers (header, value) ->
|
||||||
let header = String.lowercase_ascii header in
|
let header = String.lowercase_ascii header in
|
||||||
if header <> "host"
|
if header <> "host"
|
||||||
@ -148,16 +153,6 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
only headers \"host\" or starting with \"x-\" are supported"
|
only headers \"host\" or starting with \"x-\" are supported"
|
||||||
else Header.replace headers header value)
|
else Header.replace headers header value)
|
||||||
(Header.init ()) headers in
|
(Header.init ()) headers in
|
||||||
begin
|
|
||||||
match body with
|
|
||||||
| None->
|
|
||||||
Logger.log_empty_request uri
|
|
||||||
| Some (`Stream _) ->
|
|
||||||
Logger.log_request Encoding.untyped uri "<stream>"
|
|
||||||
| Some body ->
|
|
||||||
Cohttp_lwt.Body.to_string body >>= fun body ->
|
|
||||||
Logger.log_request ?media Encoding.untyped uri body
|
|
||||||
end >>= fun log_request ->
|
|
||||||
let body, headers =
|
let body, headers =
|
||||||
match body, media with
|
match body, media with
|
||||||
| None, _ -> Cohttp_lwt.Body.empty, headers
|
| None, _ -> Cohttp_lwt.Body.empty, headers
|
||||||
@ -171,9 +166,29 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
| Some ranges ->
|
| Some ranges ->
|
||||||
Header.add headers "accept" (Media_type.accept_header ranges) in
|
Header.add headers "accept" (Media_type.accept_header ranges) in
|
||||||
Lwt.catch begin fun () ->
|
Lwt.catch begin fun () ->
|
||||||
|
let rec call_and_retry_on_502 attempt delay =
|
||||||
Cohttp_lwt_unix.Client.call
|
Cohttp_lwt_unix.Client.call
|
||||||
~headers
|
~headers
|
||||||
(meth :> Code.meth) ~body uri >>= fun (response, ansbody) ->
|
(meth :> Code.meth) ~body uri >>= fun (response, ansbody) ->
|
||||||
|
let status = Response.status response in
|
||||||
|
match status with
|
||||||
|
| `Bad_gateway ->
|
||||||
|
let log_ansbody = clone_body ansbody in
|
||||||
|
log.log ~media:faked_media Encoding.untyped status
|
||||||
|
(lazy (Cohttp_lwt.Body.to_string log_ansbody >>= fun text ->
|
||||||
|
Lwt.return @@ Format.sprintf
|
||||||
|
"Attempt number %d/10, will retry after %g seconds.\n\
|
||||||
|
Original body follows.\n\
|
||||||
|
%s"
|
||||||
|
attempt delay text)) >>= fun () ->
|
||||||
|
if attempt >= 10 then
|
||||||
|
Lwt.return (response, ansbody)
|
||||||
|
else
|
||||||
|
Lwt_unix.sleep delay >>= fun () ->
|
||||||
|
call_and_retry_on_502 (attempt + 1) (delay +. 0.1)
|
||||||
|
| _ ->
|
||||||
|
Lwt.return (response, ansbody) in
|
||||||
|
call_and_retry_on_502 1 0. >>= fun (response, ansbody) ->
|
||||||
let headers = Response.headers response in
|
let headers = Response.headers response in
|
||||||
let media_name =
|
let media_name =
|
||||||
match Header.get headers "content-type" with
|
match Header.get headers "content-type" with
|
||||||
@ -187,9 +202,6 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
| None -> None
|
| None -> None
|
||||||
| Some media_types -> find_media media_name media_types in
|
| Some media_types -> find_media media_name media_types in
|
||||||
let status = Response.status response in
|
let status = Response.status response in
|
||||||
let log_ansbody = clone_body ansbody in
|
|
||||||
Logger.log_response log_request ?media Encoding.untyped status
|
|
||||||
(lazy (Cohttp_lwt.Body.to_string log_ansbody)) >>= fun () ->
|
|
||||||
match status with
|
match status with
|
||||||
| `OK -> Lwt.return (`Ok (Some (ansbody, media_name, media)))
|
| `OK -> Lwt.return (`Ok (Some (ansbody, media_name, media)))
|
||||||
| `No_content -> Lwt.return (`Ok None)
|
| `No_content -> Lwt.return (`Ok None)
|
||||||
@ -230,12 +242,6 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
Lwt.return (`Connection_failed msg)
|
Lwt.return (`Connection_failed msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
type log = {
|
|
||||||
log:
|
|
||||||
'a. ?media:Media_type.t -> 'a Encoding.t -> Cohttp.Code.status_code ->
|
|
||||||
string Lwt.t Lazy.t -> unit Lwt.t ;
|
|
||||||
}
|
|
||||||
|
|
||||||
let handle_error log service (body, media_name, media) status f =
|
let handle_error log service (body, media_name, media) status f =
|
||||||
Cohttp_lwt.Body.is_empty body >>= fun empty ->
|
Cohttp_lwt.Body.is_empty body >>= fun empty ->
|
||||||
if empty then
|
if empty then
|
||||||
@ -285,7 +291,7 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
media_types ?logger ?base
|
media_types ?logger ?base
|
||||||
service params query body >>= fun (log, meth, uri, body, media) ->
|
service params query body >>= fun (log, meth, uri, body, media) ->
|
||||||
begin
|
begin
|
||||||
generic_call ?headers ~accept:media_types meth ?body ?media uri >>= function
|
internal_call meth log ?headers ~accept:media_types ?body ?media uri >>= function
|
||||||
| `Ok None ->
|
| `Ok None ->
|
||||||
log.log Encoding.untyped `No_content (lazy (Lwt.return "")) >>= fun () ->
|
log.log Encoding.untyped `No_content (lazy (Lwt.return "")) >>= fun () ->
|
||||||
Lwt.return (`Ok None)
|
Lwt.return (`Ok None)
|
||||||
@ -328,7 +334,7 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
media_types ?logger ?base
|
media_types ?logger ?base
|
||||||
service params query body >>= fun (log, meth, uri, body, media) ->
|
service params query body >>= fun (log, meth, uri, body, media) ->
|
||||||
begin
|
begin
|
||||||
generic_call ?headers ~accept:media_types meth ?body ?media uri >>= function
|
internal_call meth log ?headers ~accept:media_types ?body ?media uri >>= function
|
||||||
| `Ok None ->
|
| `Ok None ->
|
||||||
on_close () ;
|
on_close () ;
|
||||||
log.log Encoding.untyped `No_content (lazy (Lwt.return "")) >>= fun () ->
|
log.log Encoding.untyped `No_content (lazy (Lwt.return "")) >>= fun () ->
|
||||||
@ -386,4 +392,18 @@ module Make (Encoding : Resto.ENCODING) = struct
|
|||||||
end >>= fun ans ->
|
end >>= fun ans ->
|
||||||
Lwt.return (meth, uri, ans)
|
Lwt.return (meth, uri, ans)
|
||||||
|
|
||||||
|
let generic_call meth ?(logger = null_logger) ?headers ?accept ?body ?media uri =
|
||||||
|
let module Logger = (val logger) in
|
||||||
|
begin match body with
|
||||||
|
| None->
|
||||||
|
Logger.log_empty_request uri
|
||||||
|
| Some (`Stream _) ->
|
||||||
|
Logger.log_request Encoding.untyped uri "<stream>"
|
||||||
|
| Some body ->
|
||||||
|
Cohttp_lwt.Body.to_string body >>= fun body ->
|
||||||
|
Logger.log_request ?media Encoding.untyped uri body
|
||||||
|
end >>= fun log_request ->
|
||||||
|
let log = { log = fun ?media -> Logger.log_response log_request ?media } in
|
||||||
|
internal_call meth log ?headers ?accept ?body ?media uri
|
||||||
|
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user