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

时间:2013-07-16 09:53:44

标签: ruby-on-rails ruby imap

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

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

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

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

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

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

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

编辑:

我在这个问题中实现了与OP类似的东西:Ruby IMAP IDLE concurrency - how to tackle?

2 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:2)

在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的blog post。)

分享1个连接

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

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