Class: TrafficJam::SimpleLimit
- Defined in:
- lib/traffic_jam/simple_limit.rb
Overview
A SimpleLimit is a limit type that is more efficient for increments but does not support decrements or changing the max value without a complete reset. This means that if the period or max value for an action, value key changes, the used and remaining values cannot be preserved.
This works by storing a key in Redis with a millisecond-precision expiry representing the time that the limit will be completely reset. Each increment operation converts the increment amount into the number of milliseconds to be added to the expiry.
Example: Limit is 5 per 10 seconds.
An increment by 1 first sets the key to expire in 2s.
Another immediate increment by 4 sets the expiry to 10s.
Subsequent increments fail until clock time catches up to expiry
Instance Attribute Summary
Attributes inherited from Limit
#action, #max, #period, #value
Instance Method Summary collapse
-
#decrement(_amount = 1, time: Time.now) ⇒ Object
Decrement the amount used by the given number.
-
#increment(amount = 1, time: Time.now) ⇒ Boolean
Increment the amount used by the given number.
- #key_prefix ⇒ Object
-
#used ⇒ Integer
Return amount of limit used, taking time drift into account.
Methods inherited from Limit
#exceeded?, #flatten, #increment!, #initialize, #limit_exceeded, #remaining, #reset
Constructor Details
This class inherits a constructor from TrafficJam::Limit
Instance Method Details
#decrement(_amount = 1, time: Time.now) ⇒ Object
Decrement the amount used by the given number.
69 70 71 |
# File 'lib/traffic_jam/simple_limit.rb', line 69 def decrement(_amount = 1, time: Time.now) raise NotImplementedError, "decrement is not defined for SimpleLimit" end |
#increment(amount = 1, time: Time.now) ⇒ Boolean
Increment the amount used by the given number. Does not perform increment if the operation would exceed the limit. Returns whether the operation was successful.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/traffic_jam/simple_limit.rb', line 28 def increment(amount = 1, time: Time.now) return true if amount == 0 return false if max == 0 raise ArgumentError.new("Amount must be positive") if amount < 0 if amount != amount.to_i raise ArgumentError.new("Amount must be an integer") end return false if amount > max incrby = (period * 1000 * amount / max).to_i argv = [incrby, period * 1000] result = begin redis.evalsha( Scripts::INCREMENT_SIMPLE_HASH, keys: [key], argv: argv) rescue Redis::CommandError redis.eval(Scripts::INCREMENT_SIMPLE, keys: [key], argv: argv) end case result when 0 return true when -1 raise Errors::InvalidKeyError, "Redis key #{key} has no expire time set" when -2 return false else raise Errors::UnknownReturnValue, "Received unexpected return value #{result} from " \ "increment_simple eval" end end |
#key_prefix ⇒ Object
90 91 92 |
# File 'lib/traffic_jam/simple_limit.rb', line 90 def key_prefix "#{config.key_prefix}:s" end |
#used ⇒ Integer
Return amount of limit used, taking time drift into account.
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/traffic_jam/simple_limit.rb', line 76 def used return 0 if max.zero? expiry = redis.pttl(key) case expiry when -1 # key exists but has no associated expire raise Errors::InvalidKeyError, "Redis key #{key} has no expire time set" when -2 # key does not exist return 0 end (max * expiry / (period * 1000.0)).ceil end |