1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
# frozen_string_literal: true
require "set"
require "redis_client"
require "redis_client/decorator"
module Sidekiq
class RedisClientAdapter
BaseError = RedisClient::Error
CommandError = RedisClient::CommandError
# You can add/remove items or clear the whole thing if you don't want deprecation warnings.
DEPRECATED_COMMANDS = %i[rpoplpush zrangebyscore zrevrange zrevrangebyscore getset hmset setex setnx].to_set
module CompatMethods
def info
@client.call("INFO") { |i| i.lines(chomp: true).map { |l| l.split(":", 2) }.select { |l| l.size == 2 }.to_h }
end
def evalsha(sha, keys, argv)
@client.call("EVALSHA", sha, keys.size, *keys, *argv)
end
# this is the set of Redis commands used by Sidekiq. Not guaranteed
# to be comprehensive, we use this as a performance enhancement to
# avoid calling method_missing on most commands
USED_COMMANDS = %w[bitfield bitfield_ro del exists expire flushdb
get hdel hget hgetall hincrby hlen hmget hset hsetnx incr incrby
lindex llen lmove lpop lpush lrange lrem mget mset ping pttl
publish rpop rpush sadd scard script set sismember smembers
srem ttl type unlink zadd zcard zincrby zrange zrem
zremrangebyrank zremrangebyscore]
USED_COMMANDS.each do |name|
define_method(name) do |*args, **kwargs|
@client.call(name, *args, **kwargs)
end
end
private
# this allows us to use methods like `conn.hmset(...)` instead of having to use
# redis-client's native `conn.call("hmset", ...)`
def method_missing(*args, &block)
warn("[sidekiq#5788] Redis has deprecated the `#{args.first}`command, called at #{caller(1..1)}") if DEPRECATED_COMMANDS.include?(args.first)
@client.call(*args, *block)
end
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
def respond_to_missing?(name, include_private = false)
super # Appease the linter. We can't tell what is a valid command.
end
end
CompatClient = RedisClient::Decorator.create(CompatMethods)
class CompatClient
def config
@client.config
end
end
def initialize(options)
opts = client_opts(options)
@config = if opts.key?(:sentinels)
RedisClient.sentinel(**opts)
elsif opts.key?(:nodes)
# Sidekiq does not support Redis clustering but Sidekiq Enterprise's
# rate limiters are cluster-safe so we can scale to millions
# of rate limiters using a Redis cluster. This requires the
# `redis-cluster-client` gem.
# Sidekiq::Limiter.redis = { nodes: [...] }
RedisClient.cluster(**opts)
else
RedisClient.config(**opts)
end
end
def new_client
CompatClient.new(@config.new_client)
end
private
def client_opts(options)
opts = options.dup
if opts[:namespace]
raise ArgumentError, "Your Redis configuration uses the namespace '#{opts[:namespace]}' but this feature is no longer supported in Sidekiq 7+. See https://github.com/sidekiq/sidekiq/blob/main/docs/7.0-Upgrade.md#redis-namespace."
end
opts.delete(:size)
opts.delete(:pool_timeout)
if opts[:network_timeout]
opts[:timeout] = opts[:network_timeout]
opts.delete(:network_timeout)
end
opts[:name] = opts.delete(:master_name) if opts.key?(:master_name)
opts[:role] = opts[:role].to_sym if opts.key?(:role)
opts[:driver] = opts[:driver].to_sym if opts.key?(:driver)
# Issue #3303, redis-rb will silently retry an operation.
# This can lead to duplicate jobs if Sidekiq::Client's LPUSH
# is performed twice but I believe this is much, much rarer
# than the reconnect silently fixing a problem; we keep it
# on by default.
opts[:reconnect_attempts] ||= 1
opts
end
end
end
|