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
falseif 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 the cached
statefor the throttle if there is a currently active block for that throttle in the cache. -
#request!(n = 1) ⇒ Object
Increments the cached throttle by the given number of tokens.
-
#state ⇒ Object
Returns
falseif 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.
50 51 52 53 54 55 |
# File 'lib/pecorino/cached_throttle.rb', line 50 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
69 70 71 |
# File 'lib/pecorino/cached_throttle.rb', line 69 def key @throttle.key end |
#request(n = 1) ⇒ Object
Returns the cached state for the throttle if there is a currently active block for that throttle in the cache. Otherwise forwards to underlying throttle.
38 39 40 41 42 43 44 45 |
# File 'lib/pecorino/cached_throttle.rb', line 38 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
Increments the cached throttle by the given number of tokens. If there is currently a known cached block on that throttle an exception will be raised immediately instead of querying the actual throttle data. Otherwise the call gets forwarded to the underlying throttle.
23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/pecorino/cached_throttle.rb', line 23 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.
76 77 78 79 80 81 82 83 84 |
# File 'lib/pecorino/cached_throttle.rb', line 76 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.
60 61 62 63 64 |
# File 'lib/pecorino/cached_throttle.rb', line 60 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 |