init commit

This commit is contained in:
Nicholas Stuart 2021-08-23 17:35:00 -07:00
parent 2daef106af
commit 7f1129277b
No known key found for this signature in database
GPG Key ID: 701DDAA370AA2E99
5 changed files with 147 additions and 3 deletions

@ -140,11 +140,12 @@ def build_redis_client(url:, **redis_options)
# Race condition TTL is not set by default. This can be used to avoid
# "thundering herd" cache writes when hot cache entries are expired.
# See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: default_coder, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, coder: default_coder, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, raise_errors: false, **redis_options)
@redis_options = redis_options
@max_key_bytesize = MAX_KEY_BYTESIZE
@error_handler = error_handler
@raise_errors = raise_errors
super namespace: namespace,
compress: compress, compress_threshold: compress_threshold,
@ -460,7 +461,12 @@ def failsafe(method, returning: nil)
yield
rescue ::Redis::BaseError => e
handle_exception exception: e, method: method, returning: returning
returning
if @raise_errors
raise e
else
returning
end
end
def handle_exception(exception:, method:, returning:)

@ -9,4 +9,5 @@
require_relative "behaviors/connection_pool_behavior"
require_relative "behaviors/encoded_key_cache_behavior"
require_relative "behaviors/failure_safety_behavior"
require_relative "behaviors/failure_raising_behavior"
require_relative "behaviors/local_cache_behavior"

@ -0,0 +1,93 @@
# frozen_string_literal: true
module FailureRaisingBehavior
def test_fetch_read_failure_raises
@cache.write("foo", "bar")
emulating_unavailability do |cache|
cache.fetch("foo")
end
end
def test_fetch_with_block_read_failure_raises
@cache.write("foo", "bar")
emulating_unavailability do |cache|
cache.fetch("foo") { '1' }
end
end
def test_read_failure_raises
@cache.write("foo", "bar")
emulating_unavailability do |cache|
cache.read("foo")
end
end
def test_read_multi_failure_raises
@cache.write_multi("foo" => "bar", "baz" => "quux")
emulating_unavailability do |cache|
cache.read_multi("foo", "baz")
end
end
def test_write_failure_raises
emulating_unavailability do |cache|
cache.write("foo", "bar")
end
end
def test_write_multi_failure_raises
emulating_unavailability do |cache|
cache.write_multi("foo" => "bar", "baz" => "quux")
end
end
def test_fetch_multi_failure_raises
@cache.write_multi("foo" => "bar", "baz" => "quux")
emulating_unavailability do |cache|
cache.fetch_multi("foo", "baz") { |k| "unavailable" }
end
end
def test_delete_failure_raises
@cache.write("foo", "bar")
emulating_unavailability do |cache|
cache.delete("foo")
end
end
def test_exist_failure_raises
@cache.write("foo", "bar")
emulating_unavailability do |cache|
cache.exist?("foo")
end
end
def test_increment_failure_raises
@cache.write("foo", 1, raw: true)
emulating_unavailability do |cache|
cache.increment("foo")
end
end
def test_decrement_failure_raises
@cache.write("foo", 1, raw: true)
emulating_unavailability do |cache|
cache.decrement("foo")
end
end
def test_clear_failure_returns_nil
emulating_unavailability do |cache|
assert_nil cache.clear
end
end
end

@ -9,7 +9,17 @@ def test_fetch_read_failure_returns_nil
end
end
def test_fetch_read_failure_does_not_attempt_to_write
##
# Though the `write` part of fetch fails for the same reason
# `read` will, the block result is still executed and returned.
def test_fetch_read_failure_returns_block_result
@cache.write("foo", "bar")
emulating_unavailability do |cache|
val = cache.fetch("foo") { '1' }
assert_equal '1', val
end
end
def test_read_failure_returns_nil

@ -283,6 +283,40 @@ def ensure_connected
end
end
class FailureRaisingFromUnavailableClientTest < StoreTest
include FailureRaisingBehavior
private
def emulating_unavailability
old_client = Redis.send(:remove_const, :Client)
Redis.const_set(:Client, UnavailableRedisClient)
assert_raise Redis::BaseConnectionError do
yield ActiveSupport::Cache::RedisCacheStore.new(namespace: @namespace, raise_errors: true)
end
ensure
Redis.send(:remove_const, :Client)
Redis.const_set(:Client, old_client)
end
end
class FailureRaisingFromMaxClientsReachedErrorTest < StoreTest
include FailureRaisingBehavior
private
def emulating_unavailability
old_client = Redis.send(:remove_const, :Client)
Redis.const_set(:Client, MaxClientsReachedRedisClient)
assert_raise Redis::CommandError do
yield ActiveSupport::Cache::RedisCacheStore.new(namespace: @namespace, raise_errors: true)
end
ensure
Redis.send(:remove_const, :Client)
Redis.const_set(:Client, old_client)
end
end
class FailureSafetyFromUnavailableClientTest < StoreTest
include FailureSafetyBehavior