-
Notifications
You must be signed in to change notification settings - Fork 2
Limiters
Daniel Pepper edited this page Mar 15, 2022
·
7 revisions
The basic interface for all limiters.
.limit
- acquire a lock. Raises a Berater::Overloaded
error if limits have been exceeded. When passed a block, it will execute the block unless the limit has been exceeded. Otherwise it returns the lock, which should be released once completed.
-
capacity
- override the limiter's capacity for this call -
cost
- the relative cost of this piece of work, default is 1
.utilization
- a Float representing how much capacity is being used, as a fraction of the limit. Values >= 1 indicate that the limiter is overloaded and calls to .limit
will fail.
limiter.limit(**opts) do
# limited work
end
lock = limiter.limit
# do work inline, then manually release lock
lock.release
limiter.limit(cost: 2) do
# do extra expensive work
end
limiter.limit(capacity: 3) do
# do work within a different capacity limit
end
Limit the amount of work done concurrently, ie. simultaneously.
Berater::ConcurrencyLimiter.new(key, capacity, **opts)
-
key
- name of limiter -
capacity
- maximum number of simultaneous requests -
opts
-
timeout
- maximum seconds a lock may be held (optional, but recommended) -
redis
- a redis instance
-
limiter = Berater::ConcurrencyLimiter.new(:key, 3, timeout: 30)
limiter.limit do
# allow only three simultaneous requests at a time, for no more than 30 seconds each
end
# or, more conveniently
Berater(:key, 3, timeout: 30) do
...
end
Useful when you want to limit usage within a given time window. It uses the leaky bucket algorithm and supports millisecond level granularity.
Berater::RateLimiter.new(key, capacity, interval, **opts)
-
key
- name of limiter -
capacity
- maximum number of requests permitted -
interval
- how often the capacity limit resets. Either number of seconds or a symbol::second
,:minute
,:hour
-
opts
-
redis
- a redis instance
-
limiter = Berater::RateLimiter.new(:key, 2, :second)
limiter.limit do
# do work, up to twice per second
end
# or, more conveniently
Berater(:key, 2, interval: :second) do
...
end
A limiter which always succeeds.
limiter = Berater::Unlimiter.new
1_000_000.times do
limiter.limit { puts 'yay' }
end
A limiter which always fails.
limiter = Berater::Inhibitor.new
limiter.limit { never! } # raises Berater::Overloaded