I'm trying to get started working with agents in F# via the MailboxProcessor<'Msg>
class, and I quickly realized I had no proper handling for exceptions. In a Haskellian world, there wouldn't be any exceptions, and so the proper way to handle issues would be to simply provide them as a response case; so an agent could reply with something like:
type AgentResponse =
| HandledData of string
| InvalidData of string
One could then call the agent's .PostAndReply
method and get an InvalidData
containing a message indicating why the data is invalid. However, this isn't Haskell, and sometimes exceptions happen. So if I do this:
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)
The second call to agent.PostAndReply
blocks indefinitely. When not using AsyncReplyChannel
and therefore just calling agent.Post
, the calls don't block, but once the agent encounters an exception, new messages just stay in the queue. Restarting the agent in either case appears impossible, as the agent.Start
function returns an InvalidOperationException
when called again, and the natural way to handle this seems to be to create a new agent with a clean state, but then all queued messages are lost.
Beyond just wrapping the entire body of an agent in try..with
, is there any good way to get an agent to continue running after an exception? Alternatively, has a "standard" way of dealing with this been established that someone can point me to?