Class: Gitlab::Redis::Wrapper

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/redis/wrapper.rb

Constant Summary collapse

InvalidPathError =
Class.new(StandardError)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rails_env = nil) ⇒ Wrapper

Returns a new instance of Wrapper.



106
107
108
# File 'lib/gitlab/redis/wrapper.rb', line 106

def initialize(rails_env = nil)
  @rails_env = rails_env || ::Rails.env
end

Class Method Details

.config_fallbackObject



81
82
83
# File 'lib/gitlab/redis/wrapper.rb', line 81

def config_fallback
  nil
end

.config_file_nameObject



62
63
64
65
66
67
68
69
70
71
# File 'lib/gitlab/redis/wrapper.rb', line 62

def config_file_name
  [
    # Instance specific config sources:
    config_file_path("redis.#{store_name.underscore}.yml"),

    # The current Redis instance may have been split off from another one
    # (e.g. TraceChunks was split off from SharedState).
    config_fallback&.config_file_name
  ].compact.first
end

.config_file_path(filename) ⇒ Object



51
52
53
54
# File 'lib/gitlab/redis/wrapper.rb', line 51

def config_file_path(filename)
  path = File.join(rails_root, 'config', filename)
  return path if File.file?(path)
end

.instrumentation_classObject



85
86
87
88
89
# File 'lib/gitlab/redis/wrapper.rb', line 85

def instrumentation_class
  return unless defined?(::Gitlab::Instrumentation::Redis)

  "::Gitlab::Instrumentation::Redis::#{store_name}".constantize
end

.poolObject



32
33
34
35
36
37
38
39
# File 'lib/gitlab/redis/wrapper.rb', line 32

def pool
  @pool ||= if config_fallback &&
      config_fallback.params.except(:instrumentation_class) == params.except(:instrumentation_class)
              config_fallback.pool
            else
              ConnectionPool.new(size: pool_size, name: store_name.underscore) { redis }
            end
end

.pool_sizeObject



41
42
43
44
45
46
47
48
49
# File 'lib/gitlab/redis/wrapper.rb', line 41

def pool_size
  # heuristic constant 5 should be a config setting somewhere -- related to CPU count?
  size = 5
  if Gitlab::Runtime.multi_threaded?
    size += Gitlab::Runtime.max_threads
  end

  size
end

.rails_rootObject

We need this local implementation of Rails.root because MailRoom doesn’t load Rails.



58
59
60
# File 'lib/gitlab/redis/wrapper.rb', line 58

def rails_root
  File.expand_path('../../..', __dir__)
end

.redisObject



91
92
93
# File 'lib/gitlab/redis/wrapper.rb', line 91

def redis
  init_redis(params)
end

.redis_yml_pathObject



73
74
75
# File 'lib/gitlab/redis/wrapper.rb', line 73

def redis_yml_path
  File.join(rails_root, 'config/redis.yml')
end

.store_nameObject



77
78
79
# File 'lib/gitlab/redis/wrapper.rb', line 77

def store_name
  name.demodulize
end

.versionObject



28
29
30
# File 'lib/gitlab/redis/wrapper.rb', line 28

def version
  with { |redis| redis.info['redis_version'] }
end

.withObject



24
25
26
# File 'lib/gitlab/redis/wrapper.rb', line 24

def with
  pool.with { |redis| yield redis }
end

Instance Method Details

#dbObject



140
141
142
# File 'lib/gitlab/redis/wrapper.rb', line 140

def db
  redis_store_options[:db] || 0
end

#encrypted_secretsObject



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/gitlab/redis/wrapper.rb', line 166

def encrypted_secrets
  # In rake tasks, we have to populate the encrypted_secrets even if the
  # file does not exist, as it is the job of one of those tasks to create
  # the file. In other cases, like when being loaded as part of spinning
  # up test environment via `scripts/setup-test-env`, we should gate on
  # the presence of the specified secret file so that
  # `Settings.encrypted`, which might not be loadable does not get
  # called. Same is the case when this library gets called by Mailroom
  # which does not have rails environment available.
  Settings.encrypted(secret_file) if (secret_file && File.exist?(secret_file)) ||
    (defined?(Gitlab::Runtime) && Gitlab::Runtime.rake?)
end

#paramsObject



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/gitlab/redis/wrapper.rb', line 110

def params
  options = redis_store_options
  options[:command_builder] = CommandBuilder

  # avoid passing classes into options as Sidekiq scrubs the options with Marshal.dump + Marshal.load
  # ref https://github.com/sidekiq/sidekiq/blob/v7.1.6/lib/sidekiq/redis_connection.rb#L37
  #
  # this does not play well with spring enabled as the forked process references the old constant
  # we use strings to look up Gitlab::Instrumentation::Redis.storage_hash as a bypass
  options[:custom] = { instrumentation_class: self.class.store_name }

  if options[:sentinels]
    # name is required in RedisClient::SentinelConfig
    # https://github.com/redis-rb/redis-client/blob/1ab081c1d0e47df5d55e011c9390c70b2eef6731/lib/redis_client/sentinel_config.rb#L17
    options[:name] = options[:host]
    options.except(:scheme, :instrumentation_class, :host, :port)
  elsif options[:cluster]
    options[:nodes] = options[:cluster].map { |c| c.except(:scheme) }
    options.except(:scheme, :instrumentation_class, :cluster)
  else
    # remove disallowed keys as seen in
    # https://github.com/redis-rb/redis-client/blob/1ab081c1d0e47df5d55e011c9390c70b2eef6731/lib/redis_client/config.rb#L21
    options.except(:scheme, :instrumentation_class)
  end
end

#secret_fileObject



148
149
150
151
152
153
154
155
156
# File 'lib/gitlab/redis/wrapper.rb', line 148

def secret_file
  return unless defined?(Settings)

  if raw_config_hash[:secret_file].blank?
    File.join(Settings.encrypted_settings['path'], 'redis.yaml.enc')
  else
    Settings.absolute(raw_config_hash[:secret_file])
  end
end

#sentinelsObject



144
145
146
# File 'lib/gitlab/redis/wrapper.rb', line 144

def sentinels
  raw_config_hash[:sentinels]
end

#sentinels?Boolean

Returns:



158
159
160
# File 'lib/gitlab/redis/wrapper.rb', line 158

def sentinels?
  sentinels && !sentinels.empty?
end

#store(extras = {}) ⇒ Object



162
163
164
# File 'lib/gitlab/redis/wrapper.rb', line 162

def store(extras = {})
  ::Redis::Store::Factory.create(params.merge(extras))
end

#urlObject



136
137
138
# File 'lib/gitlab/redis/wrapper.rb', line 136

def url
  raw_config_hash[:url]
end