# frozen_string_literal: true require "connection_pool" require "redis" require "uri" # Adapted from Sidekiq 6.x Implementation module Bearcat module RedisConnection KNOWN_REDIS_URL_ENVS = %w[REDIS_URL REDISTOGO_URL REDISCLOUD_URL].freeze class << self def configured?(prefix, explicit: false) determine_redis_provider(prefix: prefix, explicit: true) end def create(options = {}) symbolized_options = options.transform_keys(&:to_sym) if !symbolized_options[:url] && (u = determine_redis_provider(prefix: options[:env_prefix])) symbolized_options[:url] = u end size = if symbolized_options[:size] symbolized_options[:size] elsif symbolized_options[:env_prefix] && (v = ENV["#{symbolized_options[:env_prefix]}_REDIS_POOL_SIZE"]) Integer(v) elsif ENV["RAILS_MAX_THREADS"] Integer(ENV["RAILS_MAX_THREADS"]) else 5 end pool_timeout = symbolized_options[:pool_timeout] || 1 ConnectionPool.new(timeout: pool_timeout, size: size) do namespace = symbolized_options[:namespace] client = Redis.new client_opts(symbolized_options) if namespace begin require "redis/namespace" Redis::Namespace.new(namespace, redis: client) rescue LoadError Rails.logger.error("Your Redis configuration uses the namespace '#{namespace}' but the redis-namespace gem is not included in the Gemfile." \ "Add the gem to your Gemfile to continue using a namespace. Otherwise, remove the namespace parameter.") exit(-127) end else client end end end private def client_opts(options) opts = options.dup if opts[:namespace] opts.delete(:namespace) end opts.delete(:size) opts.delete(:env_prefix) if opts[:network_timeout] opts[:timeout] = opts[:network_timeout] opts.delete(:network_timeout) end opts[:reconnect_attempts] ||= 1 opts end def determine_redis_provider(prefix: nil, explicit: false) vars = [] if prefix.present? if (ptr = ENV["#{prefix}_REDIS_PROVIDER"]).present? return ENV[ptr] else vars.push(*KNOWN_REDIS_URL_ENVS.map { |e| ENV["#{prefix}_#{e}"] }) end end if !explicit || !prefix.present? if (ptr = ENV["REDIS_PROVIDER"]).present? vars << ptr # Intentionally not a return else vars.push(*KNOWN_REDIS_URL_ENVS) end end vars.select!(&:present?) vars.each do |e| return ENV[e] if ENV[e].present? end nil end end end end