Skip to content
This repository has been archived by the owner on Oct 16, 2018. It is now read-only.

Commit

Permalink
Merge pull request #1 from deliveroo/support-redis-distributed
Browse files Browse the repository at this point in the history
Support Redis:DistributedStore
  • Loading branch information
mezis authored Feb 16, 2017
2 parents dc308ad + 287ca52 commit efe37a5
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
1 change: 1 addition & 0 deletions lib/rack/attack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Rack::Attack
autoload :DalliProxy, 'rack/attack/store_proxy/dalli_proxy'
autoload :MemCacheProxy, 'rack/attack/store_proxy/mem_cache_proxy'
autoload :RedisStoreProxy, 'rack/attack/store_proxy/redis_store_proxy'
autoload :RedisDistributedStoreProxy, 'rack/attack/store_proxy/redis_distributed_store_proxy'
autoload :Fail2Ban, 'rack/attack/fail2ban'
autoload :Allow2Ban, 'rack/attack/allow2ban'
autoload :Request, 'rack/attack/request'
Expand Down
4 changes: 2 additions & 2 deletions lib/rack/attack/store_proxy.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
module Rack
class Attack
module StoreProxy
PROXIES = [DalliProxy, MemCacheProxy, RedisStoreProxy]
PROXIES = [DalliProxy, MemCacheProxy, RedisStoreProxy, RedisDistributedStoreProxy]

ACTIVE_SUPPORT_WRAPPER_CLASSES = Set.new(['ActiveSupport::Cache::MemCacheStore', 'ActiveSupport::Cache::RedisStore']).freeze
ACTIVE_SUPPORT_CLIENTS = Set.new(['Redis::Store', 'Dalli::Client', 'MemCache']).freeze
ACTIVE_SUPPORT_CLIENTS = Set.new(['Redis::Store', 'Redis::DistributedStore', 'Dalli::Client', 'MemCache']).freeze

def self.build(store)
client = unwrap_active_support_stores(store)
Expand Down
40 changes: 40 additions & 0 deletions lib/rack/attack/store_proxy/redis_distributed_store_proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'delegate'
require 'rack/attack/store_proxy/redis_store_proxy'

module Rack
class Attack
module StoreProxy
class RedisDistributedStoreProxy < RedisStoreProxy
def self.handle?(store)
defined?(::Redis::DistributedStore) && store.is_a?(::Redis::DistributedStore)
end

# overrride #increment to use a Lua script as Redis::Distributed
# does not support pipelining (even when all keys got to the same node)
def increment(key, amount, options={})
evalsha(script_sha, keys: [key], argv:[amount, options[:expires_in]])
rescue Redis::BaseError
end

private

def script_sha
@script_sha ||= begin
shas = script 'load', %{
-- KEYS[1]: key to increment
-- ARGV[1]: amount to increment by
-- ARGV[2]: updated TTL if any
local value = redis.call('INCRBY', KEYS[1], tonumber(ARGV[1]))
local ttl = tonumber(ARGV[2])
if ttl then
redis.call('EXPIRE', KEYS[1], ttl)
end
return value
}
shas.kind_of?(Array) ? shas.first : shas
end
end
end
end
end
end
1 change: 1 addition & 0 deletions spec/integration/rack_attack_cache_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def sleep_until_expired
ActiveSupport::Cache::MemoryStore.new,
ActiveSupport::Cache::DalliStore.new("127.0.0.1"),
ActiveSupport::Cache::RedisStore.new("127.0.0.1"),
ActiveSupport::Cache::RedisStore.new(%w[127.0.0.1/1 127.0.0.1/2]),
ActiveSupport::Cache::MemCacheStore.new("127.0.0.1"),
Dalli::Client.new,
ConnectionPool.new { Dalli::Client.new },
Expand Down

0 comments on commit efe37a5

Please sign in to comment.