Is it possible to make PostAndAsyncReply return immediately when its MailboxProcessor is disposed (or otherwise stopped)? Or is there some "pattern" / best practice on how to safely use PostAndReply methods without creating deadlocks?
Right now I have the problem that PostAndAsyncReply never returns when the MailboxProcessor has been disposed. Using the timeout parameter isn't an option since I cannot wait (besides that choosing reasonable timeouts is quite hard or impossible anyway since it depends on way too many factors).
[<Test>]
let ``waiting for a reply from a disposed agent``() =
use server = MailboxProcessor.Start(fun inbox -> async {
()
})
(server :> System.IDisposable).Dispose()
server.PostAndReply (fun reply -> reply) // <- deadlock
|> ignore)
edit: Most examples with MailboxProcessors I have seen (incl. the ones on MSDN) don't even mind disposing the MailboxProcessors. And the MSDN doesn't explain how MailboxProcessors react when being disposed. Is it unnecessary to dispose them?
There is no built-in support for the cancellation of pending
PostAndReply
calls, but you can implement this. To handle for disposal, you can wrap the body of the mailbox intry .. finally
. In thefinally
block, you can somehow signal that the mailbox processor has stopped. The following uses cancellation token source for this:There are two things to keep in mind:
If the mailbox processor is running some long-running work (like sleeping above), then the disposal will happen after this is completed (this is because of the nature of async workflows - they do not forcefully cancel computations)
I had to use
StartAsTask
instead ofRunSynchronously
to start the task at the end. For some reason (not quite sure), usingRunSynchronously
does not seem to cancel the computation.You could easily wrap this in some class that uses
MailboxProcessor
internally, exposes similar interface and adds this functionality - but that's a bit too much for a single answer!To answer your question regarding
Dispose
, I'm not entirely sure what the behaviour is, but disposing the mailbox processor disposes an internalAutoResetEvent
(see the source code) that is used to signal that a message has arrived. I suppose this just means that the mailbox processor will not accept any further messages.