F# 异步尝试不捕获异常

F# async try with not catching exceptions

奇怪的事情...我只是想在 F# 中对异常进行简单的重试,但捕获没有捕获 :) 有什么想法吗?

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()
    } 

如果下一个是这样的函数; let handler evt = async { failwith "Oh-no" } 然后执行try中的代码但没有被捕获。到底是怎么回事? :O

更新

reraise 是一种扩展方法,如下所述:https://github.com/fsharp/fslang-suggestions/issues/660 by nikontethird。

type Exception with
    member this.Reraise () =
        (ExceptionDispatchInfo.Capture this).Throw ()
        Unchecked.defaultof<_>

您的代码确实捕获了异常。这是我正在 运行 测试的完整程序:

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

输出:

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

您可以看到正在捕获异常,因为 handlerretry 放弃之前被多次调用。

备注:

  • 我用 raise error 替换了 return error.Reraise(),因为 Exception.Reraise 不是定义的方法。我不确定你在这里想到的是什么,但这并不直接影响你问题的答案。
  • 使用所有三个参数完全调用 retry 很重要(我使用 () 作为“事件”),然后 运行 同步计算结果 async .也许你没有那样做?
  • 您可能想考虑使用 Async.Catch 来处理异步异常。