Module: RedisMemo

Includes:
TestOverrides
Defined in:
lib/redis_memo/testing.rb,
lib/redis_memo.rb

Overview

Redis memo can be flaky due to transient network errors (e.g. Redis connection errors), or when used with async handlers. This class allows users to override the default redis-memo behavior to be more robust when testing their code that uses redis-memo.

Defined Under Namespace

Modules: MemoizeMethod, MemoizeQuery, TestOverrides Classes: AfterCommit, ArgumentError, Batch, Cache, ConnectionPool, Future, Memoizable, Middleware, Options, Redis, RuntimeError, Testing, Tracer, WithoutMemoization

Constant Summary collapse

DefaultOptions =

A process-level RedisMemo::Options instance that stores the global options. This object can be modified by RedisMemo.configure.

memoize_method allows users to provide method-level configuration. When no callsite-level configuration specified we will use the values in DefaultOptions as the default value.

RedisMemo::Options.new
THREAD_KEY_WITHOUT_MEMO =
TODO:

Move thread keys to RedisMemo::ThreadKey

:__redis_memo_without_memo__
THREAD_KEY_CONNECTION_ATTEMPTS_COUNT =
:__redis_memo_connection_attempts_count__
THREAD_KEY_MAX_CONNECTION_ATTEMPTS =
:__redis_memo_max_connection_attempts__

Class Method Summary collapse

Methods included from TestOverrides

#without_memo?

Class Method Details

.batch(&blk) ⇒ Object

Batch Redis calls triggered by memoize_method to minimize the round trips to Redis.

  • Batches cannot be nested

  • When a batch is still open (while still in the RedisMemo.batch block)

the return value of any memoized method is a RedisMemo::Future instead of the actual method value

  • The actual method values are returned as a list, in the same order as

invoking, after exiting the block

See RedisMemo::Batch for more information.

Examples:

results = RedisMemo.batch do
  5.times { |i| memoized_calculation(i) }
  nil # Not the return value of the block
end
results.size == 5 # true


53
54
55
56
57
58
59
# File 'lib/redis_memo.rb', line 53

def self.batch(&blk)
  RedisMemo::Batch.open
  blk.call
  RedisMemo::Batch.execute
ensure
  RedisMemo::Batch.close
end

.checksum(serialized) ⇒ Object

TODO:

Move this method out of the top namespace



62
63
64
# File 'lib/redis_memo.rb', line 62

def self.checksum(serialized)
  Digest::SHA1.base64digest(serialized)
end

.configure {|default_options| ... } ⇒ void

This method returns an undefined value.

Configure global-level default options. Those options will be used unless some options specified at memoize_method callsite level. See RedisMemo::Options for all the possible options.

RedisMemo::DefaultOptions

Yield Parameters:



32
33
34
# File 'lib/redis_memo.rb', line 32

def self.configure(&blk)
  blk.call(DefaultOptions)
end

.deep_sort_hash(orig_hash) ⇒ Object

TODO:

Move this method out of the top namespace



72
73
74
75
76
77
78
# File 'lib/redis_memo.rb', line 72

def self.deep_sort_hash(orig_hash)
  {}.tap do |new_hash|
    orig_hash.sort.each do |k, v|
      new_hash[k] = v.is_a?(Hash) ? deep_sort_hash(v) : v
    end
  end
end

.uuidObject

TODO:

Move this method out of the top namespace



67
68
69
# File 'lib/redis_memo.rb', line 67

def self.uuid
  SecureRandom.uuid
end

.with_max_connection_attempts(max_attempts) { ... } ⇒ Object

Set the max connection attempts to Redis per code block. If we fail to connect to Redis more than ‘max_attempts` times, the rest of the code block will fall back to the uncached flow, `RedisMemo.without_memo`.

Parameters:

  • The (Integer)

    max number of connection attempts.

Yields:

  • no_args the block of code to set the max attempts for.



104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/redis_memo.rb', line 104

def self.with_max_connection_attempts(max_attempts)
  prev_value = Thread.current[THREAD_KEY_WITHOUT_MEMO]
  if max_attempts
    Thread.current[THREAD_KEY_CONNECTION_ATTEMPTS_COUNT] = 0
    Thread.current[THREAD_KEY_MAX_CONNECTION_ATTEMPTS] = max_attempts
  end
  yield
ensure
  Thread.current[THREAD_KEY_WITHOUT_MEMO] = prev_value
  Thread.current[THREAD_KEY_CONNECTION_ATTEMPTS_COUNT] = nil
  Thread.current[THREAD_KEY_MAX_CONNECTION_ATTEMPTS] = nil
end

.without_memo { ... } ⇒ Object

Configure the wrapped code in the block to skip memoization.

Yields:

  • no_args The block of code to skip memoization.



91
92
93
94
95
96
97
# File 'lib/redis_memo.rb', line 91

def self.without_memo
  prev_value = Thread.current[THREAD_KEY_WITHOUT_MEMO]
  Thread.current[THREAD_KEY_WITHOUT_MEMO] = true
  yield
ensure
  Thread.current[THREAD_KEY_WITHOUT_MEMO] = prev_value
end

.without_memo?Boolean

Whether the current execution context has been configured to skip memoization and use the uncached code path.

Returns:

  • (Boolean)


84
85
86
# File 'lib/redis_memo.rb', line 84

def self.without_memo?
  ENV["REDIS_MEMO_DISABLE_ALL"] == 'true' || Thread.current[THREAD_KEY_WITHOUT_MEMO] == true
end