gpt4 book ai didi

asynchronous - 如果程序立即失败,则 MailboxProcessor 第一个循环无法运行

转载 作者:行者123 更新时间:2023-12-04 05:02:20 26 4
gpt4 key购买 nike

我有一个命令定期运行 SFTP 检查并将结果记录到文件中。

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 |> printerAgent.Post
printfn "%s" ex.Message // <- NOTICE THIS LINE
sw.Close()
sw.Dispose()
0

它遍历 MailboxProcessor

let printerAgent = MailboxProcessor.Start(fun inbox-> 
// the message processing function
let rec messageLoop() = async{
// read a message
let! msg = inbox.Receive()
// process a message
sw.WriteLine("{0}: {1}", DateTime.UtcNow.ToShortTimeString(), msg)
printfn "%s" msg
// loop to top
return! messageLoop()
}
// start the loop
messageLoop()
)

调用它来将消息写入日志

let sftpExample local host port username (password:string) =
async {
use client = new SftpClient(host, port, username, password)
client.Connect()
sprintf "Connected to %s\nroot dir list" host |> printerAgent.Post
do! downloadDir local client ""
sprintf "Done, disconnecting now" |> printerAgent.Post
client.Disconnect()
} |> Async.RunSynchronously

文件下载是异步的,相应的消息也是如此,但一切似乎都运行良好。

问题是 - 如果由于某些原因,sftp 连接立即失败,MailboxProcessor 没有时间记录异常消息。

我尝试做的 - 这确实有效 - 是在结束前添加 printfn "%s"ex.Message:我只是想知道是否有人设想了更好的解决方案。

仅供引用,完整代码在 this gist 中.

最佳答案

实际上,您希望程序在退出之前等待 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 完成其所有工作。 (为避免永远阻塞的任何机会,我建议在您的 PostAndReply 调用中设置 10 秒这样的超时;默认超时为 -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()

关于asynchronous - 如果程序立即失败,则 MailboxProcessor 第一个循环无法运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55243768/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com