与赛璐珞保持多种联系的正确方法?

时间:2013-12-05 15:57:56

标签: ruby celluloid

我目前正在开发一个从许多IMAP邮箱中提取邮件的应用程序。似乎赛璐珞对于这部分来说非常适合,但我不确定如何聘请演员。

应用程序将以分布式方式运行。有 x 邮箱用于民意调查和 y 进程,其中将分割这些邮箱。因此,每个进程都有一个他们必须轮询的邮箱列表,这个列表会不时地改变。这意味着每个进程维护的连接池都是动态的。

我最大的问题是:我应该为每个邮箱生成一个单独的ImapConnection actor,还是应该创建一个内部管理所有连接的ImapListener actor?

我目前的设计采用前一种解决方案。有一个中央协调员演员,它保持一组演员,每个演员管理一个imap连接。添加了一个简单的新连接:

@connections << ImapConnection.supervise(account_info)

ImapConnection定期轮询IMAP服务器,或维持IDLE连接。如果协调器想要停止轮询邮箱,它会在@connections数组中查找并正确处理它。

这对我来说似乎是一种合乎逻辑的方法,可以产生Celluloid的许多好处(例如自动重启崩溃的演员),但我很难找到使用这种方法的其他软件的例子。以这种方式产生100个演员正确使用演员模型还是应该使用不同的方法?

1 个答案:

答案 0 :(得分:5)

很高兴听到您正在使用Celluloid。好问题。

不确定如何创建连接并维护它们,无论是由您有能力管理的TCPSocket。如果您能够直接管理TCPSocket,则应使用Celluloid::IO以及Celluloid本身。我也不知道你从IMAP连接中提取信息的位置。这两件事影响了你的策略。

你的做法并不坏,但是 - 可以通过添加一些东西来完成你的繁重工作,投票工作人员;另一个只持有account_info;以及触发工作和/或维持IDLE状态的最终演员。因此,您最终会得到ImapWorker(一个游泳池),ImapMaintainerImapRegistry。就在这里,我想知道,既然你是民意调查,你是否需要保持开放的连接,而不是允许推送信息。如果你打算进行民意调查并仍然保持联系开放,那么这三个角色将会是这样做的:

ImapRegistryaccount_info保留在Hash中。这将包含addgetremove等方法。我建议使用Hash @credentials,以便您在ImapMaintainerImapRegistry之间使用相同的ID;一个在其@connections中保存实时连接,另一个在account_info中保存@credentials个实例。 @connections@credentials都由相同的ID访问,但是一个保持易失性连接,而另一个只有静态数据可用于在必要时重新创建连接。通过这种方式,您的重型升降机可能会死亡,重生,并且整个系统可以自行再生。

ImapMaintainer中包含实际的@connections,并且内置了every( interval ) { }个任务,并在account_info存储ImapRegistry时添加。我看到有两个任务,具体取决于您计划轮询的频率。一种可能是简单地触摸IMAP连接以维护它,另一种可能是用ImapWorker轮询IMAP服务器。 ImapWorker就像ImapMaintainer一样保存在@worker中。它有@connections@worker#polling#keepalivepolling可能是@connections.each情况,或者您可以在创建连接时添加每个连接的计时器。

ImapWorker有两种方法......一种是#touch,可以使连接保持活动状态。主要的是#poll,它接受​​您维护的连接,并在其上运行轮询过程。该方法返回信息甚至更好地存储它,然后工作者返回@worker池。这将使您获得将轮询过程发生在单独的线程而不仅仅是单独的光纤中的好处,并且还允许在最强大但最无法识别的角色中保留最棘手的方面。

向后工作,如果ImapRegistry收到#add,则会存储account_info并将其提供给创建连接的ImapMaintainer和计时器(但会忘记account_info并且只创建连接和计时器,或者只创建连接并让一个大的计时器保持与@worker的连接,这是一个池。ImapMaintainer不可避免地命中一个计时器,所以在开始时它的计时器结束时它可以检查它的连接。如果连接由于某种原因而消失,它可以用@registry.get信息重新创建它。在它的计时器提示任务中,它可以运行@worker.poll或{{1} }。

这说明了上述要求,显示了初始化程序如何将actor系统组合在一起,并且具有不完整的方法框架。

@worker.alive

我喜欢 WORKERS = 9 #de arbitrarily chosen class ImapRegistry include Celluloid def initialize @maintainer = ImapMaintainer.supervise @credentials = {} end def add( account_info ) ... end def get( id ) ... end def remove( id ) ... end end class ImapMaintainer include Celluloid def initialize @worker = ImapWorker.pool size: WORKERS @connections = {} end def add( id, credential ) ... end def remove( id ) ... end #de These exist if there is one big timer: def polling ... end def keepalive ... end end class ImapWorker include Celluloid def initialize #de Nothing needed. end def poll( connection ) ... end def touch( connection ) ... end end registry = ImapRegistry.supervise 并希望你能获得很多成功。请问您是否需要澄清任何内容,但这至少是另一种策略供您考虑。