繁体   English   中英

失败后重新启动MailboxProcessor?

[英]Restart MailboxProcessor after failure?

我试图通过MailboxProcessor<'Msg>类开始使用F#中的代理,我很快意识到我没有适当的处理异常的方法。 在Haskellian的世界中,不会有任何例外,因此处理问题的正确方法是简单地将其作为响应案例提供。 因此,座席可以回复以下内容:

type AgentResponse =
    | HandledData of string
    | InvalidData of string

然后可以调用代理的.PostAndReply方法,并获取一个InvalidData其中包含指示数据为何无效的消息。 但是,这不是Haskell,有时会发生异常。 因此,如果我这样做:

let agent =
    new MailboxProcessor<string * AsyncReplyChannel<AgentResponse>>(fun inbox ->
        async {
            while true do
                let! (msg, replyChannel) = inbox.Receive()
                if msg = "die" then failwith "Unknown exception encountered!"
                else replyChannel.Reply(HandledData(msg))
        })

agent.Start()
agent.PostAndReply (fun rc -> "die", rc)
agent.PostAndReply (fun rc -> "Test", rc)

agent.PostAndReply的第二次调用无限期阻塞。 当不使用AsyncReplyChannel并因此仅调用agent.Post ,调用不会阻塞,但是一旦代理遇到异常,新消息就只会留在队列中。 在这两种情况下,都无法重新启动代理,因为agent.Start函数在再次InvalidOperationException时会返回InvalidOperationException ,而处理此问题的自然方法似乎是创建一个具有纯净状态的新代理,但是所有排队的消息都会丢失。

除了在try..with包装代理的整个主体try..with ,还有什么好方法可以让代理在发生异常后继续运行? 或者,是否已经建立了可以指出我的“标准”处理方式?

您在Haskell中确实有例外:尝试在ghci中使用Data.List.head []

不幸的是,在Haskell或F#中,缺少依赖类型意味着我们可以编写没有计算意义的类型正确的代码。

实际上,用try ... with块包装不是处理异常的好主意。 您不需要包装整个正文,而只是包装代码的非纯部分。

然后,按照经典方法,您将产生一个使用适当的构造函数生成的值。

一个可能的选项是类似于在此问题上 Tomas Petricek定义的HandlingMailbox的帮助程序类型,该类型重复运行代理程序的主体:

type ResilientMailbox<'T> private(f:ResilientMailbox<'T> -> Async<unit>) as self =
    let event = Event<_>()
    let inbox = new MailboxProcessor<_>(fun _inbox ->
        let rec loop() = async {
            try
                return! f self
            with e ->
                event.Trigger(e)
                return! loop()
            }
        loop())
    member __.OnError = event.Publish
    member __.Start() = inbox.Start()
    member __.Receive() = inbox.Receive()
    member __.Post(v:'T) = inbox.Post(v)
    static member Start(f) =
        let mbox = new ResilientMailbox<_>(f)
        mbox.Start()
        mbox

可以像正常的MailboxProcessor一样启动和运行它,但是如果提供的代理主体引发异常,它将重新运行。

编辑:更改内部MailboxProcessor以使用递归函数而不是while true do..块; 目标函数正常返回时,先前的代码不会停止运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM