redis-rb
redis-rb copied to clipboard
DB index unintentionally copied over from REDIS_URL env var
v4.1.4 include a fix for 888, but introduced an issue for me. In my environment, I have REDIS_URL=redis://HOSTNAME:6379/5 which is used for most of my interactions with Redis. However, in one code path I'm connecting to a separate Redis Cluster like this:
client = Redis.new({ cluster: "redis://DIFFERENT_HOSTNAME:6379", password: "PASSWORD" })
If I don't specify db: 0 in the initializer, or add a /0 to the end of the cluster string, my new client connects to DB index of 5, which is inadvertently copied over from the REDIS_URL config.
This is likely an uncommon case, and I'm not even sure there is an adequate heuristic that works well, but I figured I'd reach out and see if anyone has an idea on this. Happy to write up a patch if there's a good approach.
Since Redis cluster only uses 0 db, it might be that the following code should be hard-coded zero.
https://github.com/redis/redis-rb/blob/b373362eba86fcef75571af2a2accffc8cee8b78/lib/redis/cluster/option.rb#L66-L68
That could work for db, but I'm wondering if there are cases where other parameters could also be copied over inadvertently. E.g. username. I believe that is usually left blank, but what if the REDIS_URL config specifies one?
REDIS_URL environment variable is used indeed if it is specified.
https://github.com/redis/redis-rb/blob/b373362eba86fcef75571af2a2accffc8cee8b78/lib/redis/client.rb#L454-L477
The option is legitimate even if we specified cluster option. We can overwrite it with cluster option. It might be a bug if we cannot overwrite it with empty value.
https://github.com/redis/redis-rb/blob/b373362eba86fcef75571af2a2accffc8cee8b78/lib/redis/cluster/option.rb#L20-L22
I was just bitten by a similar thing today and came here to file an issue about it, but I'll add on another example to this one instead:
$ cat main.rb
require 'redis'
# these two are equivalent:
a = Redis.new()
b = Redis.new(url: ENV['REDIS_URL'])
p a, b
# intuitively, I expect these two to be equivalent, but they are not:
c = Redis.new(url: 'redis://explicit-host')
d = Redis.new(host: 'explicit-host')
p c, d
$ REDIS_URL=redis://env-host:12345 bundler exec ruby ./main.rb
#<Redis client v4.5.1 for redis://env-host:12345/0>
#<Redis client v4.5.1 for redis://env-host:12345/0>
#<Redis client v4.5.1 for redis://explicit-host:6379/0>
#<Redis client v4.5.1 for redis://explicit-host:12345/0>
That's surprising behavior, to say the least. If I pass a hostname but not a port to something, I would expect to get the default port for whatever I'm connecting to, not pulling bits out of an environment variable I thought I was overriding.
similar issue: #679
This is solved in 5.0