Class: ActiveSupport::Cache::RedisStore
- Inherits:
-
Store
- Object
- Store
- ActiveSupport::Cache::RedisStore
- Defined in:
- lib/active_support/cache/redis_store.rb
Constant Summary collapse
- ERRORS_TO_RESCUE =
[ Errno::ECONNREFUSED, Errno::EHOSTUNREACH, # This is what rails' redis cache store rescues # https://github.com/rails/rails/blob/5-2-stable/activesupport/lib/active_support/cache/redis_cache_store.rb#L447 Redis::BaseConnectionError ].freeze
- DEFAULT_ERROR_HANDLER =
-> (method: nil, returning: nil, exception: nil) do if logger logger.error { "RedisStore: #{method} failed, returned #{returning.inspect}: #{exception.class}: #{exception.}" } end end
Instance Attribute Summary collapse
-
#data ⇒ Object
readonly
Returns the value of attribute data.
Instance Method Summary collapse
-
#clear ⇒ Object
Clear all the data from the store.
-
#decrement(name, amount = 1, options = {}) ⇒ Object
Decrement a key in the store.
-
#delete_matched(matcher, options = nil) ⇒ Object
Delete objects for matched keys.
-
#exist?(name, options = nil) ⇒ Boolean
fixed problem with invalid exists? method github.com/rails/rails/commit/cad2c8f5791d5bd4af0f240d96e00bae76eabd2f.
- #expire(key, ttl) ⇒ Object
- #fetch_multi(*names) ⇒ Object
-
#increment(name, amount = 1, options = {}) ⇒ Object
Increment a key in the store.
-
#initialize(*addresses) ⇒ RedisStore
constructor
Instantiate the store.
-
#read_multi(*names) ⇒ Object
Reads multiple keys from the cache using a single call to the servers for all keys.
- #reconnect ⇒ Object
- #stats ⇒ Object
- #with(&block) ⇒ Object
- #write(name, value, options = nil) ⇒ Object
Constructor Details
#initialize(*addresses) ⇒ RedisStore
Instantiate the store.
Example:
RedisStore.new
# => host: localhost, port: 6379, db: 0
RedisStore.new client: Redis.new(url: "redis://127.0.0.1:6380/1")
# => host: localhost, port: 6379, db: 0
RedisStore.new "redis://example.com"
# => host: example.com, port: 6379, db: 0
RedisStore.new "redis://example.com:23682"
# => host: example.com, port: 23682, db: 0
RedisStore.new "redis://example.com:23682/1"
# => host: example.com, port: 23682, db: 1
RedisStore.new "redis://example.com:23682/1/theplaylist"
# => host: example.com, port: 23682, db: 1, namespace: theplaylist
RedisStore.new "redis://localhost:6379/0", "redis://localhost:6380/0"
# => instantiate a cluster
RedisStore.new "redis://localhost:6379/0", "redis://localhost:6380/0", pool_size: 5, pool_timeout: 10
# => use a ConnectionPool
RedisStore.new "redis://localhost:6379/0", "redis://localhost:6380/0",
pool: ::ConnectionPool.new(size: 1, timeout: 1) { ::Redis::Store::Factory.create("localhost:6379/0") })
# => supply an existing connection pool (e.g. for use with redis-sentinel or redis-failover)
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/active_support/cache/redis_store.rb', line 54 def initialize(*addresses) @options = addresses. addresses = addresses.compact.map(&:dup) @data = if @options[:pool] raise "pool must be an instance of ConnectionPool" unless @options[:pool].is_a?(ConnectionPool) @pooled = true @options[:pool] elsif [:pool_size, :pool_timeout].any? { |key| @options.has_key?(key) } = {} [:size] = [:pool_size] if [:pool_size] [:timeout] = [:pool_timeout] if [:pool_timeout] @pooled = true ::ConnectionPool.new() { ::Redis::Store::Factory.create(*addresses, @options) } elsif @options[:client] @options[:client] else ::Redis::Store::Factory.create(*addresses, @options) end @error_handler = @options[:error_handler] || DEFAULT_ERROR_HANDLER super(@options) end |
Instance Attribute Details
#data ⇒ Object (readonly)
Returns the value of attribute data.
22 23 24 |
# File 'lib/active_support/cache/redis_store.rb', line 22 def data @data end |
Instance Method Details
#clear ⇒ Object
Clear all the data from the store.
247 248 249 250 251 252 253 |
# File 'lib/active_support/cache/redis_store.rb', line 247 def clear instrument(:clear, nil, nil) do failsafe(:clear) do with(&:flushdb) end end end |
#decrement(name, amount = 1, options = {}) ⇒ Object
Decrement a key in the store
If the key doesn’t exist it will be initialized on 0. If the key exist but it isn’t a Fixnum it will be initialized on 0.
Example:
We have two objects in cache:
counter # => 23
rabbit # => #<Rabbit:0x5eee6c>
cache.decrement "counter"
cache.read "counter", :raw => true # => "22"
cache.decrement "counter", 2
cache.read "counter", :raw => true # => "20"
cache.decrement "a counter"
cache.read "a counter", :raw => true # => "-1"
cache.decrement "rabbit"
cache.read "rabbit", :raw => true # => "-1"
226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/active_support/cache/redis_store.rb', line 226 def decrement(name, amount = 1, = {}) instrument :decrement, name, amount: amount do failsafe :decrement do = () key = normalize_key(name, ) with do |c| c.decrby(key, amount).tap do write_key_expiry(c, key, ) end end end end end |
#delete_matched(matcher, options = nil) ⇒ Object
Delete objects for matched keys.
Performance note: this operation can be dangerous for large production databases, as it uses the Redis “KEYS” command, which is O(N) over the total number of keys in the database. Users of large Redis caches should avoid this method.
Example:
cache.delete_matched "rab*"
99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/active_support/cache/redis_store.rb', line 99 def delete_matched(matcher, = nil) = () instrument(:delete_matched, matcher.inspect) do failsafe(:read_multi, returning: false) do matcher = key_matcher(matcher, ) begin with do |store| !(keys = store.keys(matcher)).empty? && store.del(*keys) end end end end end |
#exist?(name, options = nil) ⇒ Boolean
fixed problem with invalid exists? method github.com/rails/rails/commit/cad2c8f5791d5bd4af0f240d96e00bae76eabd2f
257 258 259 260 |
# File 'lib/active_support/cache/redis_store.rb', line 257 def exist?(name, = nil) res = super(name, ) res || false end |
#expire(key, ttl) ⇒ Object
241 242 243 244 |
# File 'lib/active_support/cache/redis_store.rb', line 241 def expire(key, ttl) = (nil) with { |c| c.expire normalize_key(key, ), ttl } end |
#fetch_multi(*names) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/active_support/cache/redis_store.rb', line 139 def fetch_multi(*names) = names. return {} if names == [] results = read_multi(*names, ) need_writes = {} fetched = names.inject({}) do |memo, name| memo[name] = results.fetch(name) do value = yield name need_writes[name] = value value end memo end failsafe(:fetch_multi_write) do with do |c| c.multi do need_writes.each do |name, value| write(name, value, ) end end end end fetched end |
#increment(name, amount = 1, options = {}) ⇒ Object
Increment a key in the store.
If the key doesn’t exist it will be initialized on 0. If the key exist but it isn’t a Fixnum it will be initialized on 0.
Example:
We have two objects in cache:
counter # => 23
rabbit # => #<Rabbit:0x5eee6c>
cache.increment "counter"
cache.read "counter", :raw => true # => "24"
cache.increment "counter", 6
cache.read "counter", :raw => true # => "30"
cache.increment "a counter"
cache.read "a counter", :raw => true # => "1"
cache.increment "rabbit"
cache.read "rabbit", :raw => true # => "1"
190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/active_support/cache/redis_store.rb', line 190 def increment(name, amount = 1, = {}) instrument :increment, name, amount: amount do failsafe :increment do = () key = normalize_key(name, ) with do |c| c.incrby(key, amount).tap do write_key_expiry(c, key, ) end end end end end |
#read_multi(*names) ⇒ Object
Reads multiple keys from the cache using a single call to the servers for all keys. Options can be passed in the last argument.
Example:
cache.read_multi "rabbit", "white-rabbit"
cache.read_multi "rabbit", "white-rabbit", :raw => true
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/active_support/cache/redis_store.rb', line 119 def read_multi(*names) = names. return {} if names == [] keys = names.map{|name| normalize_key(name, )} args = [keys, ] args.flatten! instrument(:read_multi, names) do |payload| failsafe(:read_multi, returning: {}) do values = with { |c| c.mget(*args) } values.map! { |v| v.is_a?(ActiveSupport::Cache::Entry) ? v.value : v } Hash[names.zip(values)].reject{|k,v| v.nil?}.tap do |result| payload[:hits] = result.keys if payload end end end end |
#reconnect ⇒ Object
274 275 276 |
# File 'lib/active_support/cache/redis_store.rb', line 274 def reconnect @data.reconnect if @data.respond_to?(:reconnect) end |
#stats ⇒ Object
262 263 264 |
# File 'lib/active_support/cache/redis_store.rb', line 262 def stats with(&:info) end |
#with(&block) ⇒ Object
266 267 268 269 270 271 272 |
# File 'lib/active_support/cache/redis_store.rb', line 266 def with(&block) if defined?(@pooled) && @pooled @data.with(&block) else block.call(@data) end end |
#write(name, value, options = nil) ⇒ Object
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/active_support/cache/redis_store.rb', line 79 def write(name, value, = nil) = (.to_h.symbolize_keys) instrument(:write, name, ) do |_payload| if [:expires_in].present? && [:race_condition_ttl].present? && [:raw].blank? [:expires_in] = [:expires_in].to_f + [:race_condition_ttl].to_f end entry = [:raw].present? ? value : Entry.new(value, **) write_entry(normalize_key(name, ), entry, ) end end |