This code represents logic used to retry failed calls to a crypto exchange:
let retries =
[
TimeSpan.FromSeconds(1.)
TimeSpan.FromSeconds(3.)
TimeSpan.FromSeconds(5.)
TimeSpan.FromSeconds(10.)
TimeSpan.FromSeconds(30.)
]
let rec retryAsync (retryAttempts: TimeSpan list) (request: unit -> Async<Result<'a, ExchangeError>>) : Async<Result<'a, ExchangeError>> =
async {
let! r = request()
match r with
| Result.Ok x ->
return Result.Ok x
| Result.Error e ->
match e with
| ExchangeError.HttpError _
| ExchangeError.ServiceUnavailable
| ExchangeError.InvalidTimestamp ->
match retryAttempts with
| [] ->
return Result.Error e
| h::t ->
Thread.Sleep(h)
return! retryAsync t request
| _ ->
return Result.Error e
}
The logic is as follow: There are a bunch of functions that return Async<Result<'a, ExchangeError>> and perform various external operations.
I am wrapping them in this code where results that return ok will be passed through, and results that return error will go through some more scrutiny. Some errors trigger a retry (HttpError, ServiceUnavailable and InvalidTimestamp) since they are transient errors which are not linked to the request itself. Other errors are not going through a retry and are passed through directly.
I would like to know if this could be expressed in a more concise / "understandable right away by a 3rd party" way.
It can be used that way:
// cancel orders
let cancelOrdersAsync (exchange: IExchange) instrument (orderIds: string list) : Async<Result<unit, ExchangeError>> =
exchange.CancelOrdersAsync(instrument, orderIds)
// cancel orders and retry
let cancelOrdersRetryAsync (exchange: IExchange) instrument (orderIds: string list) =
retryAsync retries (fun _ -> cancelOrdersAsync exchange instrument orderIds)
as an extra question: could this be made as a curried function where I'd just have something like retryAsync retries cancelOrders
f#
I find this code easily understandable without your explanation. If your goal is to make this understandable to someone who doesn't know even basicf#
, then I would issue a frame challenge to say that's not really a desirable goal. \$\endgroup\$