Фактически, вам нужно, чтобы программа ожидала, пока MailboxProcessor завершит обработку всей своей очереди сообщений, прежде чем программа закроется. Кажется, ваш printfn "%s" ex.Message
работает, но он не гарантированно работает: если у MailboxProcessor в очереди было несколько элементов, поток, выполняющий функцию printfn
, мог бы завершиться до того, как поток MailboxProcessor успел пройти через все свои сообщения. .
Дизайн, который я бы порекомендовал, состоит в том, чтобы изменить вход вашего printerAgent
на DU, как показано ниже:
type printerAgentMsg =
| Message of string
| Shutdown
Затем, когда вы хотите, чтобы агент принтера завершил отправку своих сообщений, используйте MailboxProcessor.PostAndReply
(и обратите внимание на пример использования в документах) в функции main
и отправьте ему сообщение Shutdown
, Помните, что сообщения MailboxProcessor ставятся в очередь: к тому времени, как он получит сообщение Shutdown
, он уже пройдет через остальные сообщения в очереди. Поэтому все, что нужно для обработки сообщения Shutdown
, это вернуть ответ unit
и просто больше не вызывать его цикл. И поскольку вы использовали PostAndReply
вместо PostAndReplyAsync
, функция main будет блокироваться до тех пор, пока MailboxProcessor не завершит всю свою работу. (Чтобы избежать любых шансов на вечную блокировку, я бы рекомендовал установить время ожидания, например, 10 секунд в вашем вызове PostAndReply
; по умолчанию время ожидания равно -1, что означает ожидание навсегда).
РЕДАКТИРОВАТЬ: Вот пример (НЕ проверенный, используйте на свой страх и риск) того, что я имею в виду:
type printerAgentMsg =
| Message of string
| Shutdown of AsyncReplyChannel<unit>
let printerAgent = MailboxProcessor.Start(fun inbox->
// the message processing function
let rec messageLoop() = async{
// read a message
let! msg = inbox.Receive()
// 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
}
// start the loop
messageLoop()
)
let logPath = Path.Combine(config.["SharedFolder"],timestamp)
let sw = new StreamWriter(logPath,true)
//...
[<EntryPoint>]
let main argv =
try
sftpExample config.["SharedFolder"] config.["SFTPFolder"] 22 "usr" "pswd" |> ignore
with
| ex ->
ex.Message |> Message |> printerAgent.Post
printfn "%s" ex.Message // <- NOTICE THIS LINE
printerAgent.PostAndReply( (fun replyChannel -> Shutdown replyChannel), 10000) // Timeout = 10000 ms = 10 seconds
sw.Close()
sw.Dispose()