Class: Pecorino::CachedThrottle
- Inherits:
-
Object
- Object
- Pecorino::CachedThrottle
- Defined in:
- lib/pecorino/cached_throttle.rb
Overview
The cached throttles can be used when you want to lift your throttle blocks into a higher-level cache. If you are dealing with clients which are hammering on your throttles a lot, it is useful to have a process-local cache of the timestamp when the blocks that are set are going to expire. If you are running, say, 10 web app containers - and someone is hammering at an endpoint which starts blocking - you don’t really need to query your DB for every request. The first request indicated as “blocked” by Pecorino can write a cache entry into a shared in-memory table, and all subsequent calls to the same process can reuse that ‘blocked_until` value to quickly refuse the request
Instance Method Summary collapse
-
#able_to_accept?(n = 1) ⇒ Boolean
Returns ‘false` if there is a currently active block for that throttle in the cache.
-
#initialize(cache_store, throttle) ⇒ CachedThrottle
constructor
A new instance of CachedThrottle.
-
#key ⇒ Object
Returns the key of the throttle.
-
#request(n = 1) ⇒ Object
Returns cached ‘state` for the throttle if there is a currently active block for that throttle in the cache.
- #request!(n = 1) ⇒ Object
-
#state ⇒ Object
Returns ‘false` if there is a currently active block for that throttle in the cache.
-
#throttled(&blk) ⇒ Object
Does not run the block if there is a currently active block for that throttle in the cache.
Constructor Details
#initialize(cache_store, throttle) ⇒ CachedThrottle
Returns a new instance of CachedThrottle.
13 14 15 16 |
# File 'lib/pecorino/cached_throttle.rb', line 13 def initialize(cache_store, throttle) @cache_store = cache_store @throttle = throttle end |
Instance Method Details
#able_to_accept?(n = 1) ⇒ Boolean
Returns ‘false` if there is a currently active block for that throttle in the cache. Otherwise forwards to underlying throttle.
46 47 48 49 50 51 |
# File 'lib/pecorino/cached_throttle.rb', line 46 def able_to_accept?(n = 1) blocked_state = read_cached_blocked_state return false if blocked_state&.blocked? @throttle.able_to_accept?(n) end |
#key ⇒ Object
Returns the key of the throttle
65 66 67 |
# File 'lib/pecorino/cached_throttle.rb', line 65 def key @throttle.key end |
#request(n = 1) ⇒ Object
Returns cached ‘state` for the throttle if there is a currently active block for that throttle in the cache. Otherwise forwards to underlying throttle.
34 35 36 37 38 39 40 41 |
# File 'lib/pecorino/cached_throttle.rb', line 34 def request(n = 1) blocked_state = read_cached_blocked_state return blocked_state if blocked_state&.blocked? @throttle.request(n).tap do |state| write_cache_blocked_state(state) if state.blocked_until end end |
#request!(n = 1) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/pecorino/cached_throttle.rb', line 19 def request!(n = 1) blocked_state = read_cached_blocked_state raise Pecorino::Throttle::Throttled.new(@throttle, blocked_state) if blocked_state&.blocked? begin @throttle.request!(n) rescue Pecorino::Throttle::Throttled => throttled_ex write_cache_blocked_state(throttled_ex.state) if throttled_ex.throttle == @throttle raise end end |
#state ⇒ Object
Returns ‘false` if there is a currently active block for that throttle in the cache. Otherwise forwards to underlying throttle.
72 73 74 75 76 77 78 79 80 |
# File 'lib/pecorino/cached_throttle.rb', line 72 def state blocked_state = read_cached_blocked_state warn "Read blocked state #{blocked_state.inspect}" return blocked_state if blocked_state&.blocked? @throttle.state.tap do |state| write_cache_blocked_state(state) if state.blocked? end end |
#throttled(&blk) ⇒ Object
Does not run the block if there is a currently active block for that throttle in the cache. Otherwise forwards to underlying throttle.
56 57 58 59 60 |
# File 'lib/pecorino/cached_throttle.rb', line 56 def throttled(&blk) # We can't wrap the implementation of "throttled". Or - we can, but it will be obtuse. return if request(1).blocked? yield end |