redis-rb
redis-rb copied to clipboard
NoMethodError (undefined method `slice!' for nil:NilClass)
I'm randomly getting the following error message. Does anyone have any ideas what could be causing this?
NoMethodError (undefined method `slice!' for nil:NilClass):
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/connection/ruby.rb:274:in `read'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:248:in `block in read'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:236:in `io'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:247:in `read'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:112:in `block in call'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:217:in `block (2 levels) in process'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:353:in `ensure_connected'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:207:in `block in process'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:292:in `logging'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:206:in `process'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis/client.rb:112:in `call'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis.rb:789:in `block in get'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis.rb:37:in `block in synchronize'
/usr/local/ruby-2.1.5/lib/ruby/2.1.0/monitor.rb:211:in `mon_synchronize'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis.rb:37:in `synchronize'
vendor/bundle/ruby/2.1.0/gems/redis-3.2.1/lib/redis.rb:788:in `get'
vendor/bundle/ruby/2.1.0/gems/redis-store-1.1.4/lib/redis/store/interface.rb:5:in `get'
vendor/bundle/ruby/2.1.0/gems/redis-store-1.1.4/lib/redis/store/marshalling.rb:17:in `get'
vendor/bundle/ruby/2.1.0/gems/redis-activesupport-4.0.0/lib/active_support/cache/redis_store.rb:169:in `read_entry'
vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.9/lib/active_support/cache.rb:312:in `block in read'
vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.9/lib/active_support/cache.rb:548:in `instrument'
vendor/bundle/ruby/2.1.0/gems/activesupport-4.1.9/lib/active_support/cache.rb:311:in `read'
/var/www/apps/13712/shared/vendor_bundle/ruby/2.1.0/bundler/gems/spree-13f1df56d58f/core/app/models/spree/preferences/store.rb:34:in `get'
/var/www/apps/13712/shared/vendor_bundle/ruby/2.1.0/bundler/gems/spree-13f1df56d58f/core/app/models/spree/preferences/scoped_store.rb:13:in `fetch'
/var/www/apps/13712/shared/vendor_bundle/ruby/2.1.0/bundler/gems/spree-13f1df56d58f/core/app/models/spree/preferences/preferable_class_methods.rb:13:in `block in preference'
/var/www/apps/13712/shared/vendor_bundle/ruby/2.1.0/bundler/gems/spree-13f1df56d58f/core/app/models/spree/preferences/preferable.rb:43:in `get_preference'
vendor/bundle/ruby/2.1.0/bundler/gems/spree-13f1df56d58f/core/lib/spree/core/controller_helpers/ssl.rb:8:in `block (2 levels) in <module:SSL>'
The last place Spree is hit before calling redis-rb:
unless (val = @cache.read(key)).nil?
return val
end
where @cache = Rails.cache
Anything that might help me get this to repro a little more often would be much appreciated.
I am on the lastest redis gem.
I am using this gem with this SSL plugin, so the error may be in the plugin. Under what circumstances could @sock.gets be nil?
Here's the locals right after $socks.get is determined to be nil
[1] pry(#<Redis::Connection::Ruby>)> line
=> nil
[2] pry(#<Redis::Connection::Ruby>)> @sock
=> #<OpenSSL::SSL::SSLSocket:0x007fdab2688730
@callback_state=nil,
@context=
#<OpenSSL::SSL::SSLContext:0x007fdab2688758
@ca_file=nil,
@ca_path=nil,
@cert=nil,
@cert_store=nil,
@client_ca=nil,
@client_cert_cb=nil,
@extra_chain_cert=nil,
@key=nil,
@npn_protocols=nil,
@npn_select_cb=nil,
@options=nil,
@renegotiation_cb=nil,
@servername_cb=nil,
@session_get_cb=nil,
@session_id_context=nil,
@session_new_cb=nil,
@session_remove_cb=nil,
@timeout=nil,
@tmp_dh_callback=nil,
@verify_callback=nil,
@verify_depth=nil,
@verify_mode=nil>,
@eof=true,
@hostname=nil,
@io=#<Redis::Connection::TCPSocket:fd 11>,
@rbuffer="",
@sync=true,
@sync_close=false,
@wbuffer="">
[3] pry(#<Redis::Connection::Ruby>)> @sock.closed?
=> false
It looks like Socket#gets is provided by the superclass IO:
Returns
nilif called at end of file -- http://ruby-doc.org/core-2.1.0/IO.html#method-i-gets
But it isn't reading from a file, right? It's reading from a TCP stream.
The TCP stream is wired up internally using a posix file descriptor (which it uses to buffer the traffic), and Ruby uses IO to interact with file descriptors. I'm unsure what would cause it to read as EOF (while still open & readable, since IO#gets raises if closed for reading).
I guess what needs to be determined here is what should happen in this state? Is the connection is functionally lost, and if so, should this raise a connection error?
If it is EOF could we do this line = line || ""?
Handling EOF as an empty string likely wouldn't work out too well, because later we attempt to parse what we read from the socket (expecting it to be a redis response) and will only obscure the source of the problem.
EOF on the socket means that there is nothing left to read and that even if we were still able to send redis commands (which is unknown), we would not be able to read responses and thus the connection is borked; it is my opinion that it's worth raising a ConnectionError here instead of masking the issue.
The problem is definitely this SSL plugin. When using SSL with Redis, the issue happens reliably when there are multiple jobs to process. I filed a ticket there, but if anyone can provide guidance on how this could potentially be fixed, I'd be happy to work on a PR.
In my case i fixed it with stunnel instead of SSL gem.
stunnel isn't always an option, like automatic deployments using Cloud66.
On Sun, Jun 14, 2015 at 6:11 AM -0700, "Alexander Merkulov" [email protected] wrote:
In my case i fixed it with stunnel instead of SSL gem.
Reply to this email directly or view it on GitHub: https://github.com/redis/redis-rb/issues/530#issuecomment-111825296
Yeah, just in my case, for Azure Redis Cache.
I assume this is fixed.