首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否在失败后重新启动MailboxProcessor?

是否在失败后重新启动MailboxProcessor?
EN

Stack Overflow用户
提问于 2015-01-02 23:35:25
回答 2查看 294关注 0票数 2

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

代码语言:javascript
复制
type AgentResponse =
    | HandledData of string
    | InvalidData of string

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

代码语言:javascript
复制
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,处理这种情况的自然方法似乎是创建一个状态干净的新代理,但随后所有排队的消息都会丢失。

除了在try..with中包装整个代理之外,还有什么好方法可以让代理在出现异常后继续运行?或者,是否已经建立了一种“标准”的方法来处理这个问题,有人可以给我指点?

EN

回答 2

Stack Overflow用户

发布于 2015-01-02 23:55:16

您在Haskell中确实有异常:在ghci中尝试Data.List.head [] ...

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

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

然后,按照传统方法,返回使用适当的构造函数生成的值。

票数 3
EN

Stack Overflow用户

发布于 2015-01-03 00:00:44

一种可能的选择是一种类似于this question的Tomas Petricek定义的HandlingMailbox的助手类型,它重复运行代理的主体:

代码语言:javascript
复制
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..块;当目标函数正常返回时,前面的代码不会停止运行。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27744533

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档