F# 异步尝试不捕获异常

时间:2021-07-19 20:59:51

标签: f#

奇怪的事情...我只是想对 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()
    } 

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

更新

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

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

1 个答案:

答案 0 :(得分:1)

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

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

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

注意事项:

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