我对ruby(每天在java中编码)的经验不是很丰富,而且我正试图找到保持连接池之类的“Ruby方式”。我有多个线程的独立Ruby应用程序,我想出了类似下面的内容。
请注意,Mongo的本机ruby驱动程序提供的MongoClient
在内部维护连接池,因此我需要的是能够保留MongoClient
的一个实例
require 'mongo'
module MongoPool
# module instance var to ensures only one exists
@mongo = nil
def self.lazy_create
@mongo ||= Mongo::MongoClient.new('localhost', 27017, :pool_size => 5, :timeout => 5)
end
# when getting connection lazily create pool by assigning to @mongo only if nil
def connection
MongoPool.lazy_create
end
end
class PeopleRepository
include MongoPool
def random_person
coll = connection['test']['people']
coll.find_one
end
end
# usage
PeopleRepository.new.find_one
我知道这样做(检查object_id
@mongo
在多次调用中保持不变),但这是保留这些内容的首选方法吗?
可能有多个存储库,因此每个存储库都可以包含MongoPool
并使用其连接。上述解决方案有任何缺点吗?还有其他方法我应该注意吗?
注意:问题更多的是如何用Ruby方式做事,而不是一般如何做(因为我的工作)。
答案 0 :(得分:5)
你真的不需要另外一个宝石来实现这一点,实际上Mongoid的驱动程序(Moped)还不支持连接池。
与在rails中使用应用程序级别常量的建议类似,您只需在无头应用程序中使用类变量,以便MongoClient实例在应用程序基类的所有调用中都是相同的单个对象/池实例。
例如,您可以执行以下操作:
require 'mongo'
class MyApplication
include Mongo
# creates a single class instance, sets pool size but won't connect until used (lazy)
@@client = MongoClient.new('localhost', 27017, :pool_size => 5, :connect => false)
def do_something
@@client['my_db']['my_collection].insert({ "foo" => "bar"})
end
end
简单而且非常直截了当。您没有必要使用上面使用的模块方法。
你提到过Torquebox所以我假设你正在使用JRuby并让Torquebox为你管理应用程序的线程池。
确保您运行的是mongo ruby驱动程序的1.8.3或更高版本,其中包含一些主要的修复程序和改进,以便在这种类型的线程设置下运行。我们解决了一些线程安全问题,并大大提高了连接池中的并发性。
希望有所帮助。
答案 1 :(得分:2)
假设您使用的是rails,我会这样做:
# config/initializers/mongo.rb
MONGODB = Mongo::MongoClient.new('localhost', 27017, :pool_size => 5, :timeout => 5)
当你使用像mongomapper这样的库时,可能有办法配置池,只是透明地使用它。
在这里查看mongo库:http://railscasts.com/episodes/194-mongodb-and-mongomapper