redis-rb icon indicating copy to clipboard operation
redis-rb copied to clipboard

NoMethodError (undefined method `slice!' for nil:NilClass)

Open MisinformedDNA opened this issue 10 years ago • 11 comments

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.

MisinformedDNA avatar May 21 '15 15:05 MisinformedDNA

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?

MisinformedDNA avatar May 21 '15 15:05 MisinformedDNA

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

MisinformedDNA avatar May 21 '15 16:05 MisinformedDNA

It looks like Socket#gets is provided by the superclass IO:

Returns nil if called at end of file -- http://ruby-doc.org/core-2.1.0/IO.html#method-i-gets

yaauie avatar May 21 '15 16:05 yaauie

But it isn't reading from a file, right? It's reading from a TCP stream.

MisinformedDNA avatar May 21 '15 16:05 MisinformedDNA

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?

yaauie avatar May 21 '15 17:05 yaauie

If it is EOF could we do this line = line || ""?

MisinformedDNA avatar May 22 '15 18:05 MisinformedDNA

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.

yaauie avatar May 22 '15 19:05 yaauie

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.

MisinformedDNA avatar May 26 '15 23:05 MisinformedDNA

In my case i fixed it with stunnel instead of SSL gem.

merqlove avatar Jun 14 '15 13:06 merqlove

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

MisinformedDNA avatar Jun 14 '15 14:06 MisinformedDNA

Yeah, just in my case, for Azure Redis Cache.

merqlove avatar Jun 14 '15 14:06 merqlove

I assume this is fixed.

byroot avatar Aug 17 '22 20:08 byroot