Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sidekiq 6.5.1] SSL_read: unexpected eof while reading #5402

Closed
jeremiemv opened this issue Jun 24, 2022 · 30 comments
Closed

[Sidekiq 6.5.1] SSL_read: unexpected eof while reading #5402

jeremiemv opened this issue Jun 24, 2022 · 30 comments

Comments

@jeremiemv
Copy link

jeremiemv commented Jun 24, 2022

Ruby version: 3.1.2
Rails version: 7.0.3
Sidekiq: 6.5.1

redis gem: 4.6.0

Running on Heroku
Happening in

  • staging, common runtime, heroku-22
  • production, shield private space, heroku-20

Heroku Redis: 6.2.3, premium-0

We have dedicated redis instances for sidekiq.

After upgrading to 6.5.1 from 6.4.2, we are having intermittent redis connection issues, in both staging and production.

OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading

/app/vendor/ruby-3.1.2/lib/ruby/3.1.0/openssl/buffering.rb line 214 in sysread_nonblock
/app/vendor/ruby-3.1.2/lib/ruby/3.1.0/openssl/buffering.rb line 214 in read_nonblock
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb line 55 in block in _read_from_socket
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb line 54 in loop
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb line 54 in _read_from_socket
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb line 47 in gets
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb line 382 in read
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 311 in block in read
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 299 in io
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 310 in read
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 161 in block in call
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 279 in block (2 levels) in process
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 420 in ensure_connected
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 269 in block in process
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 356 in logging
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 268 in process
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb line 161 in call
/app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.2.0/lib/scout_apm/instruments/redis.rb line 32 in block in call_with_scout_instruments
/app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.2.0/lib/scout_apm/tracer.rb line 34 in instrument
/app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.2.0/lib/scout_apm/tracer.rb line 44 in instrument
/app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.2.0/lib/scout_apm/instruments/redis.rb line 31 in call_with_scout_instruments
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb line 263 in block in send_command
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb line 262 in synchronize
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb line 262 in send_command
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/commands/scripting.rb line 110 in _eval
/app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/commands/scripting.rb line 97 in evalsha
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 55 in zpopbyscore
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 35 in block (2 levels) in enqueue_jobs
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 30 in each
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 30 in block in enqueue_jobs
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq.rb line 156 in block in redis
/app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb line 63 in block (2 levels) in with
/app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb line 62 in handle_interrupt
/app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb line 62 in block in with
/app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb line 59 in handle_interrupt
/app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb line 59 in with
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq.rb line 153 in redis
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 29 in enqueue_jobs
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 109 in enqueue
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/scheduled.rb line 101 in block in start
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb line 8 in watchdog
/app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.5.1/lib/sidekiq/component.rb line 17 in block in safe_thread

initializer

require "sidekiq/web"

Sidekiq.configure_server do |config|
  config.redis = {
    url: ENV["SIDEKIQ_REDIS_URL"] || ENV["REDIS_URL"] || "redis://localhost:6379/1",
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
  }
end

Sidekiq.configure_client do |config|
  config.redis = {
    url: ENV["SIDEKIQ_REDIS_URL"] || ENV["REDIS_URL"] || "redis://localhost:6379/1",
    ssl_params: { verify_mode: OpenSSL::SSL::VERIFY_NONE }
  }
end

sidekiq.yml

# Sample configuration file for Sidekiq.
# Options here can still be overridden by cmd line args.
# Place this file at config/sidekiq.yml and Sidekiq will
# pick it up automatically.
---
:verbose: false
:concurrency: 5
:timeout: 25
:max_retries: 14

# Sidekiq will run this file through ERB when reading it so you can
# even put in dynamic logic, like a host-specific queue.
# http://www.mikeperham.com/2013/11/13/advanced-sidekiq-host-specific-queues/
:queues:
  - critical
  - default
  - mailers
  - low

# you can override concurrency based on environment
production:
  :concurrency: <%= ENV.fetch("SIDEKIQ_CONCURRENCY") { 5 } %>

development:
  :max_retries: 0
@jeremiemv jeremiemv changed the title Sidekiq 6.5.1 SSL_read: unexpected eof while reading [Sidekiq 6.5.1] SSL_read: unexpected eof while reading Jun 24, 2022
@mperham
Copy link
Collaborator

mperham commented Jun 24, 2022 via email

@jeremiemv
Copy link
Author

jeremiemv commented Jun 24, 2022

@mperham we haven't touched the redis gem in forever since the February 6.4.0 update.
Reverting sidekiq fixes the issue.

@jeremiemv
Copy link
Author

jeremiemv commented Jun 24, 2022

And no recent openssl updates.
https://devcenter.heroku.com/changelog-items/2434

@mperham
Copy link
Collaborator

mperham commented Jun 24, 2022

I don’t see any issues either nor am I aware of any issues. https://github.com/redis/redis-rb/blob/master/CHANGELOG.md#470

6.5.0 added support for the new redis-client gem but I don’t see how that could have broken low-level SSL socket operations in the existing redis gem. @casperisfine ?

@byroot
Copy link
Collaborator

byroot commented Jun 24, 2022

Yeah I don't see it either.

@jeremiemv a couple questions to hopefully have a few theories to explore:

  • Are all the backtraces exactly like this? Or does it fail at random points (e.g. here it fails in Redis#evalsha is it always the case).
  • unexpected eof while reading suggest the connection was closed by the server. Anything weird in the Redis server logs?

@byroot
Copy link
Collaborator

byroot commented Jun 24, 2022

We changed:

conn.evalsha(@lua_zpopbyscore_sha, keys: keys, argv: argv)

for

conn.evalsha(@lua_zpopbyscore_sha, keys, argv)

But that should make any difference: https://github.com/redis/redis-rb/blob/70dab9c149e739b450fa0c6ad660646f58e23170/lib/redis/commands/scripting.rb#L75-L96

@byroot
Copy link
Collaborator

byroot commented Jun 24, 2022

Also since it happens on staging, I assume you can test more various things.

  • If you migrate to redis-client does the issue still happen?
  • What about hiredis-client ?
  • Any way to connect without SSL for a while? It's possible that the SSL layer is hiding the underlying issue.

NB: I'm just giving ideas to hopefully get a bit more info on what the problem is.

@jeremiemv
Copy link
Author

jeremiemv commented Jun 24, 2022

Are all the backtraces exactly like this? Or does it fail at random points (e.g. here it fails in Redis#evalsha is it always the case).

Yes. And same in staging and prod.

Screen Shot 2022-06-24 at 1 13 10 PM

unexpected eof while reading suggest the connection was closed by the server. Anything weird in the Redis server logs?

Only logs I see are the regular metrics samples. No warning or error.

I found another application log. Not sure if this is helpful additional info.

Jun 24 09:47:02 samosa-app-production app[web] ERROR E, [2022-06-24T16:47:02.839752 #25] ERROR -- : [admin] [c9c8b2c0-66dc-9b92-9170-1a926f7abb34] [ActiveJob] Failed enqueuing SyncUserJob to Sidekiq(default): OpenSSL::SSL::SSLError (SSL_read: unexpected eof while reading)

Also since it happens on staging, I assume you can test more various things.

If you migrate to redis-client does the issue still happen?

Will give it a try.

What about hiredis-client ?

Will give it a try.

disabling SSL.

Not sure it is possible with Redis 6 on Heroku.
https://devcenter.heroku.com/articles/heroku-redis#security-and-compliance
Will investigate.

Thank you for looking into this BTW!

@byroot
Copy link
Collaborator

byroot commented Jun 24, 2022

Yes. And same in staging and prod.

Oh wow, color me intrigued. Something in the EVALSHA specifically must cause the server to close the connection somehow.

@jeremiemv
Copy link
Author

No SSL and hiredis-client are both a no.

SSL:
As of Redis version 6, Hobby plans support both TLS and unencrypted connections. Production plans require TLS connections. You must enable TLS in your Redis client’s configuration in order to connect to a Redis 6 database.
We are using production plans.

hiredis-client:
Because of the above, it is a no go.
https://github.com/mperham/sidekiq/wiki/Heroku#redis
The redis gem has supported the verify_mode key since version 4.0.2. The hiredis gem does not work in this environment, so do not include it in your Gemfile if you are using redis with rediss:// and OpenSSL::SSL::VERIFY_NONE.

Going to see if I can make redis-client work.

@jeremiemv
Copy link
Author

Ah. It just happened in staging with sidekiq 6.4.2


OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading
  /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/openssl/buffering.rb, line 214, in sysread_nonblock
  /app/vendor/ruby-3.1.2/lib/ruby/3.1.0/openssl/buffering.rb, line 214, in read_nonblock
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb, line 55, in block in _read_from_socket
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb, line 54, in loop
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb, line 54, in _read_from_socket
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb, line 47, in gets
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/connection/ruby.rb, line 382, in read
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 311, in block in read
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 299, in io
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 310, in read
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 161, in block in call
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 279, in block (2 levels) in process
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 420, in ensure_connected
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 269, in block in process
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 356, in logging
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 268, in process
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/client.rb, line 161, in call
  /app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.1.1/lib/scout_apm/instruments/redis.rb, line 32, in block in call_with_scout_instruments
  /app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.1.1/lib/scout_apm/tracer.rb, line 34, in instrument
  /app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.1.1/lib/scout_apm/tracer.rb, line 44, in instrument
  /app/vendor/bundle/ruby/3.1.0/gems/scout_apm-5.1.1/lib/scout_apm/instruments/redis.rb, line 31, in call_with_scout_instruments
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb, line 263, in block in send_command
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb, line 262, in synchronize
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis.rb, line 262, in send_command
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/commands/scripting.rb, line 110, in _eval
  /app/vendor/bundle/ruby/3.1.0/gems/redis-4.6.0/lib/redis/commands/scripting.rb, line 97, in evalsha
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 55, in zpopbyscore
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 35, in block (2 levels) in enqueue_jobs
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 30, in each
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 30, in block in enqueue_jobs
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq.rb, line 95, in block in redis
  /app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb, line 63, in block (2 levels) in with
  /app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb, line 62, in handle_interrupt
  /app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb, line 62, in block in with
  /app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb, line 59, in handle_interrupt
  /app/vendor/bundle/ruby/3.1.0/gems/connection_pool-2.2.5/lib/connection_pool.rb, line 59, in with
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq.rb, line 92, in redis
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 29, in enqueue_jobs
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 108, in enqueue
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/scheduled.rb, line 100, in block in start
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/util.rb, line 56, in watchdog
  /app/vendor/bundle/ruby/3.1.0/gems/sidekiq-6.4.2/lib/sidekiq/util.rb, line 65, in block in safe_thread

My apologies, the timing really coincided with the sidekiq upgrade in staging and the following prod release.

No idea what the root cause is yet :/

@mperham
Copy link
Collaborator

mperham commented Jun 25, 2022

Is there something bad about the Lua that causes Redis to reset the connection? Perhaps using a command or option that is not supported in the version you're running?

@byroot
Copy link
Collaborator

byroot commented Jun 25, 2022

hiredis-client:
Because of the above, it is a no go.

Note that hiredis-client is the hiredis binding for redis-client and it does support SSL. Hence why I suggested it. It's interesting to try it because it's a radically different implementation so it's likely to report errors in a different way (or maybe not because in the end it's OpenSSL too).

Ah. It just happened in staging with sidekiq 6.4.2

Ah that makes more sense now :)

I'm still willing to help debug this any way I can. Once you manage to get more information feel free to open an issue on redis/redis-rb or redis-rb/redis-client.

@davidrunger
Copy link
Contributor

I came to this issue by googling for "heroku-22" "unexpected eof while reading". Currently this thread is the only result for that search. I googled for that because I was seeing similar intermittent errors in my app after upgrading from the heroku-20 stack to the heroku-22 stack. Downgrading back to the heroku-20 stack immediately stopped the errors. So I pretty strongly believe that these errors are somehow caused by the heroku-22 stack. (This belief is somewhat contradicted by @jeremiemv's statement that these errors were also occurring for him in "production, shield private space, heroku-20", though. Is there any possibility that production might have accidentally been upgraded to heroku-22 without y'all intending/realizing it?)

My app connects to Redis (6.2.3, heroku-redis, hobby-dev plan) using SSL/TLS (i.e. using a rediss: URL rather than redis:). In my app, although I do use Sidekiq, the errors that I was seeing weren't coming from Sidekiq's usage of Redis, but rather from the application's direct usage of Redis. For me, it wasn't #evalsha that was causing the errors, but rather #setex and #hgetall. As mentioned, the errors were only intermittent.

Because downgrading from heroku-22 to heroku-20 resolved these issues for me for now, I don't have a pressing issue. I'm sharing my experience/info in the hopes that it will be useful in understanding/diagnosing the cause of the problem, and in the hope that, once it is resolved I will again be able to upgrade to the heroku-22 stack, this time without errors.

@ezekg
Copy link

ezekg commented Jun 27, 2022

I know it's not Sidekiq's issue, but since this is the only result when searching online, I figured I'd share more info along with @davidrunger. Heroku-22 now uses OpenSSL 3 and has no support for OpenSSL 1. Thinking that may be the issue. I hit the same errors above when I upgraded to heroku-22 and have since reverted until I can spend more time on it. There's gotta be an incompatibility or outdated dependency somewhere in my app's Redis stack.

@jeremiemv
Copy link
Author

Thank you everyone. Reverted to heroku-20 and so far so good.

Will open a ticket with Heroku so they are aware of the issue.

And probably open a ruby/openssl issue, separate from Support OpenSSL 3.0 ruby/openssl#369

@morgoth
Copy link

morgoth commented Jun 28, 2022

Hey, just hit the same issue after upgrading to heroku-22. Thank you all for investigation.
Do you know of any open bug ticket regarding this heroku issue that we can all follow and update with our findings?
Just to not spam this thread anymore.

@mperham
Copy link
Collaborator

mperham commented Jun 28, 2022

Please contact Heroku support and point them to this issue. They are welcome to add any context or link to better resources.

@jeremiemv
Copy link
Author

From my Heroku support ticket: (they agreed for me to copy/paste this)


We've seen a few reports of this, and while we continue investigating to see how we can improve this from our end, I think we have a pretty good idea of the current situation - let me share:

These "unexpected EOF while reading" SSL errors can be reproduced consistently as soon as the connection is killed from the Redis end. The two more direct ways here would be to open a redis-cli session against the Redis instance and running CLIENT KILL on any connections coming from your app, or waiting for the default idle timeout to act, which I think it's what's happening here.

OpenSSL 3 has a much more strict behavior about unexpected EOF. Most Redis clients for other languages use their own TLS implementation, and some clients like PHP and Python's have enabled the SSL_OP_IGNORE_UNEXPECTED_EOF setting to make OpenSSL 3 behave as it did in previous versions.

However, for Ruby specifically, we can see that when redis-rb is running with OpenSSL 3 and it gets one of these EOF, it is not gracefully reconnecting as it does for the behavior it saw with older OpenSSL versions. From our investigation so far we believe that the final fix will probably need to come from Ruby's OpenSSL and/or redis-rb.

To get back into what I believe might be the source of the EOFs, which is Redis terminating client connections, it is important to remember that all Heroku Redis instances will close idle connections after 5 minutes: https://devcenter.heroku.com/articles/managing-heroku-redis-using-cli#redis-timeout. I consider this feature useful to avoid that any connection leaks to Redis could end up in your app hitting the maximum number of clients, but this is something you can fully configure on your own. I have been working with some of our customers that have tried setting the idle timeout to a larger value, around 25 hours, so that the dyno cycling periods are covered. This is, by making the timeout over 25 hours, no connections made by your dynos during their lifespan would be affected by this timeout.

Heroku Redis is configured with a tcp-keepalive of 240 seconds, so any broken connections from clients would still be cleaned up by the Redis server. However, we recommend being careful with increasing this timeout initially as any connection leaks from your app might have been hidden by the timeout, and if it gets extended or disabled completely, your connections might end up exhausting the connection limit for your Redis plan. We're also evaluating making this keepalive shorter, as we believe that'd be beneficial especially if the idle timeout is deactivated.

Alternatively, and especially seeing that this is behavior coming from OpenSSL that could potentially affect other connections, you might want to build EOF resiliency/retries from within your code directly.

To confirm, this behavior does not happen in previous stacks like heroku-20 as they don't come with OpenSSL3 as heroku-22 does. Staying in heroku-20 for a while would also be an option, while we see if there's some changes around this behavior that can be applied to redis-rb.

Would you like to test the idle timeout changes and let us know how it goes? As I mentioned, this is something we're actively investigating and working on, and it's possible this situation results in changes to the default timeout and keepalive settings in Heroku as I mentioned.


We're still investigating further to see if these EOFs due to the incorrectly closed connections from the Redis server side is due to the default Redis behavior or if there might be something specific with how Heroku Redis runs that could be causing it. However, and keeping this in mind, if you want to use that info around OpenSSL, feel free to do so. For context, this is what other languages/clients did:

python/cpython#25309
php/php-src@74f75db - this commit is interesting because the message has much more context.

As I mentioned, we'll continue looking into this to see if we can make Heroku Redis compliant with the expected behavior from our end. I've linked this ticket to the internal work item where we're tracking this so I can keep you posted if we have news in the short term.

@mperham
Copy link
Collaborator

mperham commented Jun 29, 2022

@jeremiemv thanks, that makes a lot of sense. Someone should open an issue in redis-rb to discuss this OpenSSL 3 quirk.

@byroot
Copy link
Collaborator

byroot commented Jun 29, 2022

Yep, we can probably handle it more cleanly.

@jeremiemv
Copy link
Author

Awesome @byroot 🥇 Want me to open an issue?

@byroot
Copy link
Collaborator

byroot commented Jun 29, 2022

Sure. I'll look at it tomorrow. Probably isn't too big a deal. #famouslastwords.

@casperisfine
Copy link
Contributor

Fix is here: redis/redis-rb#1107, I'd appreciate if some people could test it in staging/production just to be sure my local testing was good (unfortunately redis-rb doesn't have an actual Redis server with SSL on CI, it's a huge pain to setup).

@dzuelke
Copy link

dzuelke commented Jul 1, 2022

Redis Server issue filed here: redis/redis#10915

@bradherman
Copy link

I came to this issue by googling for "heroku-22" "unexpected eof while reading". Currently this thread is the only result for that search. I googled for that because I was seeing similar intermittent errors in my app after upgrading from the heroku-20 stack to the heroku-22 stack. Downgrading back to the heroku-20 stack immediately stopped the errors. So I pretty strongly believe that these errors are somehow caused by the heroku-22 stack. (This belief is somewhat contradicted by @jeremiemv's statement that these errors were also occurring for him in "production, shield private space, heroku-20", though. Is there any possibility that production might have accidentally been upgraded to heroku-22 without y'all intending/realizing it?)

Hey David! I also did the same. Hope you're well. And thanks to the team here for finding the issue! 🙏

@Mariusio
Copy link

Did anyone in the last weeks give heroku-22 another shot to see if the issue has been fixed in the meantime?

@edmorley
Copy link

@Mariusio This has been fixed for some time.

The fix is not in Heroku-22 (since it was not the issue, other than it happening to ship with OpenSSL 3 since it's based on Ubuntu 22.04), but instead in redis-rb 4.7.1+ and redis server 7.0.3+. Upgrading either one of the Redis server or the Redis Ruby gem to a fixed version should be sufficient to make the error stop.

@Mariusio
Copy link

@edmorley Thanks so much for the update and the explanation, very helpful.

@mikeappell
Copy link

mikeappell commented Mar 1, 2023

Hey y'all, was running into the same issue: intermittent "SSL_read: unexpected eof while reading" errors while initializing Sidekiq jobs. Am pretty sure it began after upgrading from Alpine Linux 3.16 (where the openssl version is 1.1.1t) to 3.17 (where it's 3.0.8). Also happen to be running redis-rb 4.6.0.

Strongly expect upgrading to redis >= 4.7.1 will do the trick; will update this comment whenever we have the chance to go live with that.

Chiming in since most users encountering this seem to be on Heroku, which we are not, and it's widely known that information is power.

Edit: Haven't seen the issue recur yet in our logs, so calling this a success.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests