Module: RedisMemo::Memoizable::Invalidation

Defined in:
lib/redis_memo/memoizable/invalidation.rb

Overview

Module containing the logic to perform invalidation on RedisMemo::Memoizables.

Defined Under Namespace

Classes: Task

Constant Summary collapse

@@invalidation_queue =

This is a thread safe data structure to handle transient network errors during cache invalidation

When an invalidation call arrives at Redis, we only bump to the specified version (so the cached results using that version will become visible) if the actual and expected previous_version on Redis match, to ensure eventual consistency: If the versions mismatch, we will use a new version that has not been associated with any cached_results.

- No invalid cached results will be read

- New memoized calculations will write back the fresh_results using the
  new version as part of their checksums.

Note: Cached data is not guaranteed to be consistent by design. Between the moment we should invalidate a version and the moment we actually invalidated a version, we would serve out-dated cached results, as if the operations that triggered the invalidation has not yet happened.

Queue.new

Class Method Summary collapse

Class Method Details

.drain_invalidation_queueObject

Drains the invalidation queue by bumping the versions of all memoizable cache keys currently in the queue. Performs invalidation asynchronously if an async handler is configured; otherwise, invaidation is done synchronously.



53
54
55
56
57
58
59
60
61
62
# File 'lib/redis_memo/memoizable/invalidation.rb', line 53

def self.drain_invalidation_queue
  async_handler = RedisMemo::DefaultOptions.async
  if async_handler.nil?
    drain_invalidation_queue_now
  else
    async_handler.call do
      drain_invalidation_queue_now
    end
  end
end

.drain_invalidation_queue_nowObject

Drains the invalidation queue synchronously by bumping the versions of all memoizable cache keys currently in the queue. If invalidation on a cache key fails due to transient Redis errors, the key is put back into the invalidation queue and retried on the next invalidation queue drain.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/redis_memo/memoizable/invalidation.rb', line 73

def self.drain_invalidation_queue_now
  retry_queue = []
  until @@invalidation_queue.empty?
    task = @@invalidation_queue.pop
    begin
      bump_version(task)
    rescue SignalException, Redis::BaseConnectionError,
           ::ConnectionPool::TimeoutError => error

      RedisMemo::DefaultOptions.redis_error_handler&.call(error, __method__)
      RedisMemo::DefaultOptions.logger&.warn(error.full_message)
      retry_queue << task
    end
  end
ensure
  retry_queue.each { |t| @@invalidation_queue << t }
end