Class: TrafficJam::RollingLimit

Inherits:
Limit
  • Object
show all
Defined in:
lib/traffic_jam/rolling_limit.rb

Overview

This class represents a rolling limit on an action, value pair. For example, if limiting the amount of money a user can transfer in a week, the action could be :transfers and the value would be the user ID. The class exposes atomic increment operations and allows querying of the current amount used and amount remaining.

This class also handles 0 for period, where 0 is no period (each request is compared to the max).

This class departs from the design of Limit by tracking a sum of the actions in a second, in a hash keyed by the timestamp. Therefore, this limit can put a lot of data size pressure on the Redis storage, so use it wisely.

Instance Attribute Summary

Attributes inherited from Limit

#action, #max, #period, #value

Instance Method Summary collapse

Methods inherited from Limit

#decrement, #exceeded?, #flatten, #increment!, #limit_exceeded, #remaining, #reset

Constructor Details

#initialize(action, value, max: nil, period: nil) ⇒ RollingLimit

Constructor takes an action name as a symbol, a maximum cap, and the period of limit. max and period are required keyword arguments.

Parameters:

  • action (Symbol)

    action name

  • value (String)

    limit target value

  • max (Integer) (defaults to: nil)

    required limit maximum

  • period (Integer) (defaults to: nil)

    required limit period in seconds

Raises:

  • (ArgumentError)

    if max or period is nil



25
26
27
# File 'lib/traffic_jam/rolling_limit.rb', line 25

def initialize(action, value, max: nil, period: nil)
  super(action, value, max: max, period: period)
end

Instance Method Details

#increment(amount = 1, time: Time.now) ⇒ Boolean

Increment the amount used by the given number. Rolls back the increment if the operation exceeds the limit. Returns whether the operation was successful. Time of increment can be specified optionally with a keyword argument, which is not really useful since it be undone by used.

Parameters:

  • amount (Integer) (defaults to: 1)

    amount to increment by

  • time (Time) (defaults to: Time.now)

    time when increment occurs (ignored)

Returns:

  • (Boolean)

    true if increment succeded and false if incrementing would exceed the limit

Raises:

  • (ArgumentError)


38
39
40
41
42
43
44
45
46
# File 'lib/traffic_jam/rolling_limit.rb', line 38

def increment(amount = 1, time: Time.now)
  raise ArgumentError, 'Amount must be an integer' if amount != amount.to_i
  return amount <= 0 if max.zero?
  return amount <= max if period.zero?
  return true if amount.zero?
  return false if amount > max

  !run_incr([time.to_i, amount.to_i, max, period]).nil?
end

#usedInteger

Return amount of limit used

Returns:

  • (Integer)

    amount used



51
52
53
54
# File 'lib/traffic_jam/rolling_limit.rb', line 51

def used
  return 0 if max.zero? || period.zero?
  [sum, max].min
end