使用Sinatra模块化风格为每个实例而不是每个请求创建一个变量



我有一个Sinatra应用程序,以模块化风格编写,运行在Heroku上。它使用Redis,而我的Redis连接数量有限(10)。我发现它经常会抛出错误,抱怨Redis连接耗尽。所以我开始使用connection_pool,希望它能解决问题;一个Redis连接池,应用程序每次都会选择其中一个,而不是在每次请求时尝试创建一个新连接。

但我仍然有同样的问题。我可以在一个查询中完成大量Redis查询,而不会有任何抱怨。但是,如果我重新加载一个测试页面,它只做一些Redis查询,连续几次很快,我会再次出现"Redis:CommandError-ERR最大客户端数达到"错误。

所以我假设,也许,它会在每个请求上创建一个新的connection_pool实例。。。我不知道。但它并不像我所期望的那样"汇集">

我有这样的东西:

# myapp.rb
$LOAD_PATH.unshift(File.dirname(__FILE__))
$stdout.sync = true
require 'thin'
require 'myapp/frontend'
MyApp::Frontend.run!

Sinatra应用程序:

# myapp/frontend.rb
require 'sinatra/base'
require 'redis'
require 'connection_pool'
require 'uuid'
module MyApp
class Frontend < Sinatra::Base
helpers do
def redis_pool
@redis_pool ||= ConnectionPool.new(:size => 8, :timeout => 5) do
redis_uri = URI.parse(ENV['REDISCLOUD_URL'])
client = ::Redis.new(:host => redis_uri.host,
:port => redis_uri.port,
:password => redis_uri.password)
end
end
end
get '/tester/'
redis_pool.with do |r|
id = UUID.generate
r.hset(:user, id, "Some data")
r.hget(:user, id)
r.hdel(:user, id)
end
p "DONE"
end
end
end

Procfile看起来像:

web: ruby myapp.rb

有什么想法吗?目前的网站流量很低,所以这应该是可能的。

每次处理/tester/的get请求时,都会创建一个新的@redis_pool实例,因为每次都会调用helper方法redis_pool

您只能使用sinatra的设置助手初始化redis连接一次:

config do
redis_uri = URI.parse(ENV['REDISCLOUD_URL'])
set :redis, Redis.new(:host => redis_uri.host,
:port => redis_uri.port,
:password => redis_uri.password)
end

现在,应用程序的每个实例都有一个redis连接,该连接对所有请求都有效。访问这样的设置

get '/tester/'
id = UUID.generate
settings.redis.hset(:user, id, "some data")
settings.redis.hget(:user, id)
settings.redis.hdel(:user, id)
p "DONE"
end

最新更新