我目前正在构建一个Ruby on Rails应用程序,该应用程序允许用户通过Gmail登录,并且它与收件箱有一个持续的IDLE连接。电子邮件进入Gmail收件箱后,需要立即进入应用程序。
目前我在实施方面有以下几点,我真正需要的一些问题有助于搞清楚。
目前,当Rails应用程序启动时,它会为每个用户创建一个线程,该线程在循环中进行身份验证和运行,以保持IDLE连接的活动。
每隔10-15分钟,该线程将“反弹IDLE”,以便传输一些数据以确保IDLE连接保持活动状态。
我认为主要问题在于可扩展性以及应用与Postgres的连接数量。似乎每个线程都需要连接到Postgres,这将在Heroku上严格限制最大连接数(基本为20,之后为任何计划为500)。
我真的需要以下方面的帮助:
编辑:
我在这个问题中实现了与OP类似的东西:Ruby IMAP IDLE concurrency - how to tackle?
答案 0 :(得分:5)
无需为每个IMAP会话生成新线程。这些可以在一个线程中完成。
维护所有用户及其IMAP会话的数组(或哈希)。在该线程中生成一个线程,一个接一个地向每个连接发送IDLE keep-alive。定期运行循环。这肯定会比你现在的方法提供更多的并发性。
长期方法是使用EventMachine。这将允许在同一个线程中使用许多IMAP连接。如果您在同一进程中处理Web请求,则应为Event Machine创建单独的线程。这种方法可以为您提供惊人的并发性。有关Eventmachine兼容的IMAP库,请参阅https://github.com/ConradIrwin/em-imap。
答案 1 :(得分:2)
由于您使用的是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。)
你所拥有的是一个良好的开端,但是拥有与数据库的O(n)连接的O(n)个线程可能难以扩展。但是,由于大多数这些数据库连接在大多数情况下都没有执行任何操作,因此可以考虑共享一个数据库连接。
正如@Deepak Kumar所提到的,您可以使用EM IMAP适配器来维护IMAP IDLE连接。实际上,由于您在Rails中使用EM,因此您可以通过Rails模型进行更改来简单地使用Rails的数据库连接池。有关配置连接池的更多信息,请参见here。