我只有一个控制器和一些操作来处理与IMAP相关的不同功能。所以我的问题是我不想为每个动作创建一个单独的连接。例如,在一个动作中我可以做类似的事情(它不是真正的代码):
def index
@imap = Net::IMAP.new(server, 993, true)
@imap.login(user, password)
@imap.select("INBOX")
end
再次在同一控制器内的另一个动作中,如果我需要做一些与IMAP相关的事情,那么我将不得不再次创建@imap
变量。
我是第一次使用IMAP,因此根据我的理解new
方法,每个操作都会创建另一个与服务器的连接,我听说谷歌有连接数限制(15)的IMAP连接数。 / p>
我无法序列化此连接对象或将其存储在任何其他服务(如Redis或Memcached)中或缓存它,那么如何创建此连接一次并将其用于所有其他操作,至少在同一控制器内执行操作(如果可能)?如果不可能,那么任何其他解决方案来处理这个问题?
当然,我可以从邮箱中缓存我需要的数据,但由于还有一些其他不需要数据的操作,因此无法提供帮助,因此需要执行以下操作:邮箱就像删除邮件一样,因此需要连接实例。
答案 0 :(得分:2)
如何创建包裹Net::IMAP
的服务对象(单例)。你可以把它贴在app/services/imap_service.rb
或类似的东西上。有关示例的示例:
require 'singleton' # This is part of the standard library
require 'connection_pool' # https://github.com/mperham/connection_pool
class IMAPService
include Singleton
def initialize
@imap = ConnectionPool.new(size: 15) { Net::IMAP.new(server, 993, true) }
end
def inbox(user, password)
@imap.with do |conn|
conn.login(user, password)
conn.select("INBOX")
end
end
end
您可以像IMAPService.instance
一样访问此单例,例如IMAPService.instance.inbox(user, password)
。我根据我们的讨论添加了connect_pool gem,以确保它是线程安全的。 IMAPService上没有attr_reader :imap
。但是,如果您不想在此处包含所有必需的方法,则可以添加一个以便可以直接访问代码中的连接池(尽管我建议尽可能使用服务对象)。然后你可以做IMAPService.instance.imap.with { |conn| conn.login(user, password) }
而不需要依赖IMAPService中的方法。
值得注意的是,您不必使用Singleton
mixin。 Implementing "the lovely" Singleton上有一篇非常好的文章,它将告诉你两种方法。
答案 1 :(得分:0)
如果您希望连接在请求之间保持打开状态,则无法将其作为实例变量存储在控制器中,因为每个请求都有自己的控制器实例。
存储连接的一种方法是使用单例。
以下是一个例子:
class ImapService
attr_accessor :imap
def initialize
@imap = Net::IMAP.new("imap.gmail.com", 993, true)
@imap.login("username@gmail.com", "password")
@imap.select("INBOX")
end
@@instance = ImapService.new
private_class_method :new
def self.instance
return @@instance
end
end
这将在您第一次访问时打开连接,如果再次访问它,它将使用旧连接。
您可以在应用程序的任何位置使用ImapService.instance.imap
访问imap变量。