Reputation: 358
Strange things... I just wanted to do a simple retry on exceptions in F# but the catch doesn't catch :) Any ideas?
let rec retry times next event =
async {
try
return! next event
with
| _ when times > 0 -> return! retry (times - 1) next event
| error -> return error.Reraise()
}
if the next is a function like;
let handler evt = async { failwith "Oh-no" }
Then the code in try executes but it is not catched. What is going on? :O
The reraise is an extension method as described here: https://github.com/fsharp/fslang-suggestions/issues/660 by nikonthethird.
type Exception with
member this.Reraise () =
(ExceptionDispatchInfo.Capture this).Throw ()
Unchecked.defaultof<_>
Upvotes: 0
Views: 418
Reputation: 17038
Your code does catch the exceptions. Here's the full program I'm running to test it:
let rec retry times next event =
async {
try
printfn "Retry: %A" times
return! next event
with
| _ when times > 0 -> return! retry (times - 1) next event
| error -> raise error
}
let handler evt =
async {
printfn "About to fail once"
failwith "Oh-no"
}
[<EntryPoint>]
let main argv =
retry 3 handler ()
|> Async.RunSynchronously
|> printfn "%A"
0
Output:
Retry: 3
About to fail once
Retry: 2
About to fail once
Retry: 1
About to fail once
Retry: 0
About to fail once
Unhandled exception. System.Exception: Oh-no
You can see that the exceptions are being caught, because handler
is invoked multiple times before retry
gives up.
Notes:
return error.Reraise()
with raise error
, since Exception.Reraise
isn't a defined method. I'm not sure what you had in mind here, but it doesn't directly affect the answer to your question.retry
with all three arguments (I used ()
as the "event"), and then run the resulting async
computation synchronously. Maybe you weren't doing that?Async.Catch
for handling async exceptions instead.Upvotes: 1