From ffba42cf43c14c0e6152d541bdaf800040caad01 Mon Sep 17 00:00:00 2001 From: Tam Chau Date: Mon, 27 Apr 2020 23:40:49 +0900 Subject: [PATCH] Add expires_in option for ActiveSupport::Cache::RedisStore#increment method (#7515) * rails patch to fix expires_in for increment method * fixup! rails patch to fix expires_in for increment method correct test case * fix redundant file name & class name * add comment to explain monkey patch for RedisCacheStore#increment --- .../active_support/cache/redis_cache_store.rb | 25 ++++++++++ .../cache/redis_cache_store_spec.rb | 48 +++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 config/initializers/active_support/cache/redis_cache_store.rb create mode 100644 spec/initializers/active_support/cache/redis_cache_store_spec.rb diff --git a/config/initializers/active_support/cache/redis_cache_store.rb b/config/initializers/active_support/cache/redis_cache_store.rb new file mode 100644 index 000000000..aa50db214 --- /dev/null +++ b/config/initializers/active_support/cache/redis_cache_store.rb @@ -0,0 +1,25 @@ +module ActiveSupport + module Cache + class RedisCacheStore + def increment(name, amount = 1, options = nil) + # With Rails 5.2.4, RedisCacheStore#increment method does not support option :expires_in. + # In order to workaround, we call expire command if the key is incremented at the first time. + # This patch should be removed when upgrading to Rails 6. + instrument :increment, name, amount: amount do + failsafe :increment do + options = merged_options(options) + key = normalize_key(name, options) + res = redis.with do |client| + client.incrby(key, amount).tap do + if options[:expires_in] && client.ttl(key).negative? + client.expire(key, options[:expires_in].to_i) + end + end + end + res + end + end + end + end + end +end diff --git a/spec/initializers/active_support/cache/redis_cache_store_spec.rb b/spec/initializers/active_support/cache/redis_cache_store_spec.rb new file mode 100644 index 000000000..8d134f39c --- /dev/null +++ b/spec/initializers/active_support/cache/redis_cache_store_spec.rb @@ -0,0 +1,48 @@ +require "rails_helper" + +RSpec.describe ActiveSupport::Cache::RedisCacheStore do + let(:redis_client) { ActiveSupport::Cache.lookup_store(:redis_cache_store).redis } + let(:cache_db) { described_class.new } + let(:key) { "monkey_patch_test" } + + def value + cache_db.read(key, raw: true).to_i + end + + def pttl + redis_client.pttl(key) + end + + describe ".increment" do + before do + cache_db.delete(key) + end + + it "increments value without expires_in" do + cache_db.increment(key) + + expect(value).to eq(1) + expect(pttl).to eq(-1) + + cache_db.increment(key) + + expect(value).to eq(2) + expect(pttl).to eq(-1) + end + + it "increments value with expires_in" do + cache_db.increment(key, 1, expires_in: 100.seconds) + first_pttl = pttl + + expect(value).to eq(1) + expect(first_pttl > 0).to be_truthy + expect(first_pttl <= 100_000).to be_truthy + + cache_db.increment(key, 1, expires_in: 200.seconds) + second_pttl = pttl + + expect(value).to eq(2) + expect(second_pttl <= first_pttl).to be_truthy + end + end +end