来自Don Syme博客(http://blogs.msdn.com/b/dsyme/archive/2010/01/10/async-and-parallel-design-patterns-in-f-reporting-progress-with-events-plus-twitter-sample.aspx)我试图实现一个Twitter流监听器。我的目标是遵循twitter api文档的指导,该文档说“在构建高可靠性系统时,通常应该在处理之前保存或排队推文”。
所以我的代码需要有两个组件:
我选择以下内容:
我还想将插入数据库中的任何错误转储到文本文件中。 (我可能会为所有错误切换到主管代理。)
两个问题:
代码类似于:
let dumpToDatabase databaseName =
//opens databse connection
fun tweet -> inserts tweet in database
type Agent<'T> = MailboxProcessor<'T>
let agentDump =
Agent.Start(fun (inbox: MailboxProcessor<string>) ->
async{
use w2 = new StreamWriter(@"\Errors.txt")
let dumpError =fun (error:string) -> w2.WriteLine( error )
let dumpTweet = dumpToDatabase "stream"
while true do
let! msg = inbox.Receive()
try
let tw = decode msg
dumpTweet tw
with
| :? MySql.Data.MySqlClient.MySqlException as ex ->
dumpError (msg+ex.ToString() )
| _ as ex -> ()
}
)
let filter_url = "http://stream.twitter.com/1/statuses/filter.json"
let parameters = "track=RT&"
let stream_url = filter_url
let stream = twitterStream MyCredentials stream_url parameters
while true do
agentDump.Post(stream.ReadLine())
非常感谢!
使用处理器代理编辑代码:
let dumpToDatabase (tweets:tweet list)=
bulk insert of tweets in database
let agentProcessor =
Agent.Start(fun (inbox: MailboxProcessor<string list>) ->
async{
while true do
let! msg = inbox.Receive()
try
msg
|> List.map(decode)
|> dumpToDatabase
with
| _ as ex -> Console.WriteLine("Processor "+ex.ToString()))
}
)
let agentDump =
Agent.Start(fun (inbox: MailboxProcessor<string>) ->
let rec loop messageList count = async{
try
let! newMsg = inbox.Receive()
let newMsgList = newMsg::messageList
if count = 10 then
agentProcessor.Post( newMsgList )
return! loop [] 0
else
return! loop newMsgList (count+1)
with
| _ as ex -> Console.WriteLine("Dump "+ex.ToString())
}
loop [] 0)
let filter_url = "http://stream.twitter.com/1/statuses/filter.json"
let parameters = "track=RT&"
let stream_url = filter_url
let stream = twitterStream MyCredentials stream_url parameters
while true do
agentDump.Post(stream.ReadLine())
答案 0 :(得分:5)
我认为描述代理的最佳方式是正在运行的进程保持某种状态,并且可以与其他代理(或网页或数据库)进行通信。编写基于代理的应用程序时,通常可以使用多个代理来相互发送消息。
我认为创建一个从Web读取推文并将其存储在数据库中的代理是一个不错的选择(尽管您也可以将推文作为代理的状态保存在内存中)。
我不会一直打开数据库连接 - MSSQL(也可能是MySQL)实现连接池,因此当你释放它时它不会自动关闭连接。这意味着每次需要将数据写入数据库时重新打开连接更安全,效率更高。
除非您希望收到大量错误消息,否则我也可能会对文件流执行相同的操作(写入时,您可以打开它,以便将新内容添加到结尾)。< / p>
F#代理队列的工作方式是逐个处理消息(在您的示例中,您正在使用inbox.Receive()
等待消息。当队列包含多条消息时,您将获得一条消息一个(循环)。
如果您想一次处理多个消息,您可以编写一个等待10个消息的代理,然后将它们作为列表发送给另一个代理(然后执行批量处理)。 / p>
您还可以为timeout
方法指定Receive
参数,这样只要它们都在一秒钟内到达,您就可以等待最多10条消息 - 这样,您就可以优雅地实现长时间不保留消息的批量处理。