1

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

目前我在实施方面有以下几点,以及一些我真的需要帮助解决的问题。

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

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

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

我真的需要以下帮助:

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

编辑:

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

4

2 回答 2

5

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

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

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

于 2013-07-22T10:15:18.280 回答
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 的博客文章。)

共享 1 个连接

你所拥有的是一个好的开始,但是拥有 O(n) 线程和 O(n) 到数据库的连接可能很难扩展。但是,由于这些数据库连接中的大多数大部分时间都没有做任何事情,因此可能会考虑共享一个数据库连接。

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

于 2013-07-26T15:53:42.527 回答