aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/CHANGELOG.md11
-rw-r--r--activesupport/lib/active_support/cache/redis_cache_store.rb24
-rw-r--r--activesupport/test/cache/stores/redis_cache_store_test.rb24
-rw-r--r--activesupport/test/core_ext/duration_test.rb12
4 files changed, 69 insertions, 2 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 100d57aa16..8031d351a9 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -131,5 +131,16 @@
*Eileen M. Uchitelle*, *Aaron Patterson*
+* RedisCacheStore: Support expiring counters.
+ Pass `expires_in: [seconds]` to `#increment` and `#decrement` options
+ to set the Redis EXPIRE if the counter doesn't exist.
+ If the counter exists, Redis doesn't extend its expiry when it's exist.
+
+ ```
+ Rails.cache.increment("my_counter", 1, expires_in: 2.minutes)
+ ```
+
+ *Jason Lee*
+
Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/activesupport/CHANGELOG.md) for previous changes.
diff --git a/activesupport/lib/active_support/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb
index 11c574258f..95f8f639e8 100644
--- a/activesupport/lib/active_support/cache/redis_cache_store.rb
+++ b/activesupport/lib/active_support/cache/redis_cache_store.rb
@@ -256,9 +256,19 @@ module ActiveSupport
#
# Failsafe: Raises errors.
def increment(name, amount = 1, options = nil)
+ options = merged_options(options)
+ key = normalize_key(name, options)
+ expires_in = options[:expires_in].to_i
+
instrument :increment, name, amount: amount do
failsafe :increment do
- redis.with { |c| c.incrby normalize_key(name, options), amount }
+ redis.with do |c|
+ val = c.incrby key, amount
+ if expires_in > 0 && c.ttl(key) == -2
+ c.expire key, expires_in
+ end
+ val
+ end
end
end
end
@@ -272,9 +282,19 @@ module ActiveSupport
#
# Failsafe: Raises errors.
def decrement(name, amount = 1, options = nil)
+ options = merged_options(options)
+ key = normalize_key(name, options)
+ expires_in = options[:expires_in].to_i
+
instrument :decrement, name, amount: amount do
failsafe :decrement do
- redis.with { |c| c.decrby normalize_key(name, options), amount }
+ redis.with do |c|
+ val = c.decrby key, amount
+ if expires_in > 0 && c.ttl(key) == -2
+ c.expire key, expires_in
+ end
+ val
+ end
end
end
end
diff --git a/activesupport/test/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb
index 24c4c5c481..a2165e1978 100644
--- a/activesupport/test/cache/stores/redis_cache_store_test.rb
+++ b/activesupport/test/cache/stores/redis_cache_store_test.rb
@@ -141,6 +141,30 @@ module ActiveSupport::Cache::RedisCacheStoreTests
end
end
end
+
+ def test_increment_expires_in
+ assert_called_with @cache.redis, :incrby, [ "#{@namespace}:foo", 1 ] do
+ assert_called_with @cache.redis, :expire, [ "#{@namespace}:foo", 60 ] do
+ @cache.increment("foo", 1, expires_in: 60)
+ end
+ end
+
+ assert_not_called @cache.redis, :expire do
+ @cache.decrement("foo", 1, expires_in: 60)
+ end
+ end
+
+ def test_decrement_expires_in
+ assert_called_with @cache.redis, :decrby, [ "#{@namespace}:foo", 1 ] do
+ assert_called_with @cache.redis, :expire, [ "#{@namespace}:foo", 60 ] do
+ @cache.decrement("foo", 1, expires_in: 60)
+ end
+ end
+
+ assert_not_called @cache.redis, :expire do
+ @cache.decrement("foo", 1, expires_in: 60)
+ end
+ end
end
class ConnectionPoolBehaviourTest < StoreTest
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 240ae3bde0..63934e2433 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -158,6 +158,18 @@ class DurationTest < ActiveSupport::TestCase
assert_equal Date.civil(2017, 1, 3), Date.civil(2017, 1, 1) + 1.day * 2
end
+ def test_date_added_with_multiplied_duration_larger_than_one_month
+ assert_equal Date.civil(2017, 2, 15), Date.civil(2017, 1, 1) + 1.day * 45
+ end
+
+ def test_date_added_with_divided_duration
+ assert_equal Date.civil(2017, 1, 3), Date.civil(2017, 1, 1) + 4.days / 2
+ end
+
+ def test_date_added_with_divided_duration_larger_than_one_month
+ assert_equal Date.civil(2017, 2, 15), Date.civil(2017, 1, 1) + 90.days / 2
+ end
+
def test_plus_with_time
assert_equal 1 + 1.second, 1.second + 1, "Duration + Numeric should == Numeric + Duration"
end