mirror of
https://github.com/mperham/sidekiq.git
synced 2022-11-09 13:52:34 -05:00
154 lines
3.7 KiB
Ruby
154 lines
3.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "connection_pool"
|
|
require "redis_client"
|
|
require "redis_client/decorator"
|
|
require "uri"
|
|
|
|
module Sidekiq
|
|
class RedisClientAdapter
|
|
BaseError = RedisClient::Error
|
|
CommandError = RedisClient::CommandError
|
|
|
|
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
|
|
|
|
def brpoplpush(*args)
|
|
@client.blocking_call(false, "BRPOPLPUSH", *args)
|
|
end
|
|
|
|
def brpop(*args)
|
|
@client.blocking_call(false, "BRPOP", *args)
|
|
end
|
|
|
|
def set(*args)
|
|
@client.call("SET", *args) { |r| r == "OK" }
|
|
end
|
|
ruby2_keywords :set if respond_to?(:ruby2_keywords, true)
|
|
|
|
def sismember(*args)
|
|
@client.call("SISMEMBER", *args) { |c| c > 0 }
|
|
end
|
|
|
|
def exists?(key)
|
|
@client.call("EXISTS", key) { |c| c > 0 }
|
|
end
|
|
|
|
private
|
|
|
|
def method_missing(*args, &block)
|
|
@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
|
|
%i[scan sscan zscan hscan].each do |method|
|
|
alias_method :"#{method}_each", method
|
|
undef_method method
|
|
end
|
|
|
|
def disconnect!
|
|
@client.close
|
|
end
|
|
|
|
def connection
|
|
{id: @client.id}
|
|
end
|
|
|
|
def redis
|
|
self
|
|
end
|
|
|
|
def _client
|
|
@client
|
|
end
|
|
|
|
def message
|
|
yield nil, @queue.pop
|
|
end
|
|
|
|
# NB: this method does not return
|
|
def subscribe(chan)
|
|
@queue = ::Queue.new
|
|
|
|
pubsub = @client.pubsub
|
|
pubsub.call("subscribe", chan)
|
|
|
|
loop do
|
|
evt = pubsub.next_event
|
|
next if evt.nil?
|
|
next unless evt[0] == "message" && evt[1] == chan
|
|
|
|
(_, _, msg) = evt
|
|
@queue << msg
|
|
yield self
|
|
end
|
|
end
|
|
end
|
|
|
|
def initialize(options)
|
|
opts = client_opts(options)
|
|
@config = if opts.key?(:sentinels)
|
|
RedisClient.sentinel(**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]
|
|
Sidekiq.logger.error("Your Redis configuration uses the namespace '#{opts[:namespace]}' but this feature isn't supported by redis-client. " \
|
|
"Either use the redis adapter or remove the namespace.")
|
|
Kernel.exit(-127)
|
|
end
|
|
|
|
opts.delete(:size)
|
|
opts.delete(:pool_timeout)
|
|
|
|
if opts[:network_timeout]
|
|
opts[:timeout] = opts[:network_timeout]
|
|
opts.delete(:network_timeout)
|
|
end
|
|
|
|
if opts[:driver]
|
|
opts[:driver] = opts[:driver].to_sym
|
|
end
|
|
|
|
opts[:name] = opts.delete(:master_name) if opts.key?(:master_name)
|
|
opts[:role] = opts[:role].to_sym if opts.key?(:role)
|
|
opts.delete(:url) if opts.key?(:sentinels)
|
|
|
|
# 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
|
|
|
|
Sidekiq::RedisConnection.adapter = Sidekiq::RedisClientAdapter
|