I have a timeout exception (and I really intend to set a timeout) inside a message loop and I have tried to catch it as follows
let printerAgent = MailboxProcessor.Start(fun inbox->
// the message processing function
let rec messageLoop() = async{
try
// read a message
let! msg = inbox.Receive 30000
// process a message
match msg with
| Message text ->
sw.WriteLine("{0}: {1}", DateTime.UtcNow.ToShortTimeString(), text)
printfn "%s" text
// loop to top
return! messageLoop()
| Shutdown replyChannel ->
replyChannel.Reply()
// We do NOT do return! messageLoop() here
with
| exc ->
printfn "%s" exc.Message
}
// start the loop
messageLoop()
)
and I can see the timout message printed in the console, but the program never ends: what am I missing?
This is how I'm calling the printerAgent
in my code
printerAgent.PostAndReply( (fun replyChannel -> Shutdown replyChannel), 10000)
Notice that with inbox.Receive()
it eventually terminates fine after a few minutes but my objective is setting a timeout (for example of 30 seconds) instead.
I think I see the conceptual problem. I can't terminate the message loop before I receive the final shutdown message (otherwise all the following printerAgent.Post
messages sent by the program will simply remain unprocessed in the queue, without blocking the program with any error, and the final shutdown message, sent by a printerAgent.PostAndReply
will timeout, also without blocking the program with any error).
I should return the message loop so it can actually continue after the timeout exactly as it happens for a normal received message:
with
| exc ->
printfn "%s" exc.Message
return! messageLoop() // important! I guess I can't really terminate the message loop from here
And at this point the program terminates in the same time: I just see a lot of Timeout of Mailbox.Receive
printed in the console (every n=30 seconds while the message loop is idling waiting to receive a message, so they can be informative about the elapsed time).