Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Early return from a loop in a task expression (CE)

I’d like to implement a retry utility for TPL-Tasks in F#, for retrying things like HttpClient.GetAsync(...).

Specification: it will retry a given task-starting function up to n times by swallowing any exceptions that might be thrown. But for the last iteration, it should propagate any exceptions to the caller rather than swallowing it (with a meaningful stack trace).

In C#, it’d be as simple as

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  public static async Task<T> RetryTask<T>(int n, D<T> d) {
    for (int i = 0; i < n - 1; ++i) {
      try {
        return await d.Invoke();
      } catch (Exception) { }
    }
    return await d.Invoke();
  }

https://sharplab.io/#gist:e6b5416c410e879e8ddbd067cdd9a9c2

But my best attempt in F# looks as cluttered as

let retryTask n (f: unit -> 'T Task): 'T Task = task {
  match!
    task {
      let mutable found = false
      let mutable value = Unchecked.defaultof<'T>
      let mutable i = 0
      while i < n - 1 && not found do
        if 0 < i then
          do! Task.Delay(TimeSpan.FromMilliseconds(100. * float i))
        i <- i + 1
        try
          let! ret = f()
          found <- true
          value <- ret
        with _ -> ()
      return if found then Some value else None
    }
  with | Some ret -> return ret
       | None -> return! f()
}

https://sharplab.io/#gist:65c3fdadacc470127b9cfa8bb2e4cb0e

THREE mutable variables! Am I missing anything?

>Solution :

Here’s my solution:

let retry nTimes makeTask =

    let rec loop nTimes =
        task {
            try return! makeTask ()
            with _ when nTimes > 0 ->
                do! Async.Sleep 1000
                return! loop (nTimes - 1)
        }

    loop nTimes
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading