2013-06-03 23 views
2

Redis的護欄進行更新以包括的Redis/Resque版本和堆棧跟蹤(如下圖):的Redis :: TimeoutError同時使用在Heroku

redis (3.0.4) 
redis-namespace (1.3.0) 
    redis (~> 3.0.0) 
redis-store (1.1.2) 
    redis (>= 2.2.0) 
resque (1.24.1) 
    mono_logger (~> 1.0) 
    multi_json (~> 1.0) 
    redis-namespace (~> 1.2) 
    sinatra (>= 0.9.2) 
    vegas (~> 0.1.2) 
resque-scheduler (2.0.1) 
    redis (>= 2.0.1) 
    resque (>= 1.20.0) 
    rufus-scheduler 

我在Heroku上看到間歇Redis::TimeoutError: Connection timed out一邊寫適度使用Rails.cache.fetch命令向Redis存儲區中的大小數組(〜200 Fixnums)。

我也在使用Resque。

我看到here Redis :: Client可以收到超時選項,但我看不到將初始化選項傳遞給Redis的位置。

我使用的是標準的Heroku resque.rb

rails_root  = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..' 
rails_env   = ENV['RAILS_ENV'] || 'development' 

resque_config  = YAML.load_file(rails_root + '/config/resque.yml') 
ENV['REDIS_URI'] = resque_config[rails_env] 
Resque.redis  = resque_config[rails_env] 
Resque.inline  = rails_env == 'test' 

require 'resque_scheduler' 
require 'resque/scheduler' 
require 'resque_scheduler/server' 

Resque.schedule = YAML.load_file(rails_root + '/config/resque-schedule.yml') 

Resque.before_fork do 
    defined?(ActiveRecord::Base) and 
    ActiveRecord::Base.connection.disconnect! 
end 

Resque.after_fork do 
    defined?(ActiveRecord::Base) and 
    ActiveRecord::Base.establish_connection 
end 

我假設Redis的客戶在這裏實例化。這是從一個在production.rb實例化一個不同的客戶端:

rails_root   = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/../..' 
rails_env   = ENV['RAILS_ENV'] || 'development' 
resque_config = YAML.load_file(rails_root + '/config/resque.yml') 
config.cache_store = :redis_store, resque_config[rails_env], { expires_in: 14.days } 

選項散列存在對Rails.cache選項,據我所知。是在這裏實例化一個新客戶端嗎?我如何將選項傳遞給這個?


更新以包括該實驗在Heroku的控制檯意味着它們是不同的客戶端實例:

irb(main):002:0> Rails.cache 
=> #<ActiveSupport::Cache::RedisStore:0x00000003860e18 @data=#<Redis client v3.0.4 for redis://spinyfin.redistogo.com:9485/0>, @options={:expires_in=>14 days}> 
irb(main):003:0> Resque.redis.redis 
=> #<Redis client v3.0.4 for redis://spinyfin.redistogo.com:9485/0> 
irb(main):004:0> Rails.cache.instance_variable_get(:@data).object_id == Resque.redis.redis.object_id 
=> false 

堆棧跟蹤:

Redis::TimeoutError: Connection timed out 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:208:in `rescue in io' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:206:in `io' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:214:in `read' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:84:in `block in call' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:187:in `block (2 levels) in process' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:295:in `ensure_connected' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:177:in `block in process' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:256:in `logging' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:176:in `process' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis/client.rb:84:in `call' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:644:in `block in setex' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:36:in `block in synchronize' 
    from /app/vendor/ruby-1.9.3/lib/ruby/1.9.1/monitor.rb:211:in `mon_synchronize' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:36:in `synchronize' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-3.0.4/lib/redis.rb:643:in `setex' 
    from /app/vendor/bundle/ruby/1.9.1/gems/redis-store-1.1.2/lib/redis/store/interface.rb:17:in `setex' 
... 11 levels... 
    from /app/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/cache.rb:299:in `fetch' 
    ...SNIP... 
    ...my code... 
    ...SNIP... 
    from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/relation/delegation.rb:6:in `each' 
    from /app/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/relation/delegation.rb:6:in `each' 
    ...SNIP... 
    ...my code... 
    ...SNIP... 
    from (irb):5 
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start' 
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start' 
    from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>' 
    from script/rails:6:in `require' 
    from script/rails:6:in `<main>'irb(main):006:0> ! Heroku client internal error. 
! Search for help at: https://help.heroku.com 
! Or report a bug at: https://github.com/heroku/heroku/issues/new 

    Error:  Operation timed out (Errno::ETIMEDOUT) 
    Backtrace: /usr/local/heroku/ruby/lib/ruby/1.9.1/openssl/buffering.rb:121:in `sysread' 
       /usr/local/heroku/ruby/lib/ruby/1.9.1/openssl/buffering.rb:121:in `readpartial' 
       /Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:69:in `block in start' 
       /Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:53:in `loop' 
       /Users/me/.heroku/client/lib/heroku/client/rendezvous.rb:53:in `start' 
       /Users/me/.heroku/client/lib/heroku/command/run.rb:132:in `rendezvous_session' 
       /Users/me/.heroku/client/lib/heroku/command/run.rb:119:in `run_attached' 
       /Users/me/.heroku/client/lib/heroku/command/run.rb:24:in `index' 
       /Users/me/.heroku/client/lib/heroku/command.rb:206:in `run' 
       /Users/me/.heroku/client/lib/heroku/cli.rb:28:in `start' 
       /usr/local/heroku/bin/heroku:24:in `<main>' 

    Command:  heroku run rails c 
    Plugins:  heroku-redis-cli 
    Version:  heroku-toolbelt/2.39.4 (x86_64-darwin10.8.0) ruby/1.9.3 
+0

可以讓我們知道您正在使用的Redis的商店的版本?對於較新的寶石,超時配置是不同的。查看一下您接收TimeoutError的位置也很有趣 - 特別是當連接到Resque時,或連接到您用於緩存的Redis連接時? –

+0

@ BrianPO'Rourke更新了幾個新的數據。 – jordanpg

回答

1

這不是一個很大的答案,但在同事的推薦下,我從RedisToGo切換到openredis,這些問題立即消失。

+0

這仍然發生在openredis我 – user5243421

1

「連接超時」消息意味着redis-rb在啓動與Redis服務器的連接時遇到問題。通常情況下,您只需在應用啓動時初始化您的Redis連接。但是,由於Resque分叉(而不是使用像Sidekiq這樣的線程),它必須爲每個單獨的作業初始化一個新的Redis連接。

通常,這不是問題,但Heroku在創建新的Redis連接時存在間歇性問題。我已經在各種語言/客戶端庫/ Redis主機中看到過這個問題,除了減少您創建的Redis連接數量之外,緩解此問題的唯一方法是在Resque.after_fork塊中自動重試連接Redis幾次。 (例如,捕捉超時錯誤,如果已嘗試3次,則重試或重新提升例外)

+0

這意味着Resque和redis_store共享客戶端實例?看看我上面更新的控制檯實驗。 – jordanpg

+0

爲了澄清,在嘗試Rails.cache.fetch嘗試時發生錯誤,而不是在Resque作業期間發生錯誤。 – jordanpg

0

不能同時通過一個URL和一個選項哈希config.cache_store,因爲this bug

config.cache_store = :redis_store, resque_config[rails_env], { expires_in: 14.days } 

如果傳遞一個URL和選項的哈希,它忽略了URL,默認爲localhost,它可能是爲什麼你看到一個超時(我只是有同樣的問題)。

相反,做這樣的事情:

redis_uri = URI.parse(ENV["REDISTOGO_URL"]) 
config.cache_store = :redis_store, { 
    host: redis_uri.host, 
    port: redis_uri.port, 
    password: redis_uri.password, 
    namespace: "cache", 
    expires_in: 7.days 
} 
+0

我不這麼認爲...看到上面的控制檯輸出意味着遠程URL被正確設置。 – jordanpg

相關問題