Ruby on Rails,具有多个帐户的IMAP IDLE

我目前正在构建一个Ruby on Rails应用程序,允许用户通过Gmail登录,并且它与收件箱有一个持续的IDLE连接。 电子邮件进入Gmail收件箱后,需要立即进入应用程序。

目前我在实施方面有以下几点,我真正需要的一些问题有助于搞清楚。

目前,当Rails应用程序启动时,它会为每个用户创建一个线程,该线程在循环中进行身份validation和运行,以保持IDLE连接的活动状态。

每隔10-15分钟,线程将“弹跳IDLE”,以便传输一些数据以确保IDLE连接保持活动状态。

我认为的主要问题是可扩展性以及应用程序与Postgres的连接数量。 似乎每个线程需要连接到Postgres,这将在Heroku上受到最大连接数的限制(基本为20,之后为任何计划为500)。

我真的需要以下方面的帮助:

  • 保持所有这些IDLE连接存活的最佳方法是什么,但减少数据库所需的线程和连接数量?
    • 注意:如果Gmail的刷新令牌用完,可能会发生用户令牌刷新,因此需要访问数据库
  • 对于如何实施这个有什么其他建议吗?

编辑:

我在这个问题中实现了类似于OP的东西: Ruby IMAP IDLE并发 – 如何解决?

无需为每个IMAP会话生成新线程。 这些可以在一个线程中完成。

维护所有用户及其IMAP会话的数组(或哈希)。 在该线程中生成一个线程,一个接一个地向每个连接发送IDLE keep-alive。 定期运行循环。 这肯定会比您当前的方法提供更多的并发性。

一个长期的方法是使用EventMachine。 这将允许在同一个线程中使用许多IMAP连接。 如果要在同一进程中处理Web请求,则应为Event Machine创建单独的线程。 这种方法可以为您提供惊人的并发性。 有关Eventmachine兼容的IMAP库,请参阅https://github.com/ConradIrwin/em-imap 。

在Rails中启动EventMachine

因为你在Heroku上,你可能正在使用thin,它已经为你启动了EventMachine。 但是,如果您移动到另一台主机并使用其他Web服务器( 例如 Phusion Passenger),您可以使用Rails初始化程序启动EventMachine:

module IMAPManager def self.start if defined?(PhusionPassenger) PhusionPassenger.on_event(:starting_worker_process) do |forked| # for passenger, we need to avoid orphaned threads if forked && EM.reactor_running? EM.stop end Thread.new { EM.run } die_gracefully_on_signal end else # faciliates debugging Thread.abort_on_exception = true # just spawn a thread and start it up Thread.new { EM.run } unless defined?(Thin) # Thin is built on EventMachine, doesn't need this thread end end def self.die_gracefully_on_signal Signal.trap("INT") { EM.stop } Signal.trap("TERM") { EM.stop } end end IMAPManager.start 

(改编自Joshua Siler的博客文章 。)

分享1个连接

你所拥有的是一个良好的开端,但是具有与数据库的O(n)连接的O(n)线程可能难以扩展。 但是,由于大多数这些数据库连接在大多数情况下都没有执行任何操作,因此可以考虑共享一个数据库连接。

正如@Deepak Kumar所提到的,您可以使用EM IMAP适配器来维护IMAP IDLE连接。 实际上,由于您在Rails中使用EM,因此您可以通过Rails模型进行更改来简单地使用Rails的数据库连接池。 有关配置连接池的更多信息,请参见此处 。