Sliding-window rate counter for measuring event throughput in real-time
gem install philiprehberger-rate_counterSliding-window rate counter for measuring event throughput in real-time
Add to your Gemfile:
gem "philiprehberger-rate_counter"
Or install directly:
gem install philiprehberger-rate_counter
require "philiprehberger/rate_counter"
counter = Philiprehberger::RateCounter::Counter.new(window: 60)
counter.increment
counter.increment(5)
counter.rate # => events per second
counter.count # => total events in window
counter.rate_per(:minute) # => events per minute
require "philiprehberger/rate_counter"
counter = Philiprehberger::RateCounter::Counter.new(window: 60)
100.times { counter.increment }
counter.peak_rate # => highest rate per second observed
counter.snapshot # => { count: 100, rate: 16.7, peak_rate: 16.7, window: 60, timestamp: ... }
registry = Philiprehberger::RateCounter::Registry.new
registry[:api].increment(50)
registry.snapshot # => { api: { count: 50, rate: ..., ... } }
Check how long ago the counter last recorded an event:
require "philiprehberger/rate_counter"
counter = Philiprehberger::RateCounter::Counter.new(window: 60)
counter.time_since_last # => nil (never incremented)
counter.increment
counter.time_since_last # => 0.0001 (seconds since last increment)
Returns nil when the counter has never been incremented or when all events
have expired from the sliding window.
Quickly decide whether the counter is "busy" based on a rate threshold — useful for back-pressure decisions and alert wiring.
counter = Philiprehberger::RateCounter::Counter.new(window: 60)
120.times { counter.increment }
counter.busy?(threshold: 1) # => true (2 events/second > 1)
counter.busy?(threshold: 100, unit: :minute) # => true (120 events/min > 100)
Manage multiple named counters with a shared window configuration:
reg = Philiprehberger::RateCounter::Registry.new(window: 60)
reg[:requests].increment
reg[:errors].increment
reg[:requests].rate # => request rate
reg[:errors].count # => error count in window
reg.names # => [:requests, :errors]
reg.reset_all # => reset all counters
Philiprehberger::RateCounter::Counter| Method | Description |
|---|---|
.new(window:) | Create a counter with a sliding window (seconds) |
#increment(n) | Record n events (default: 1) |
#rate | Events per second over the window |
#count | Total events within the window |
#rate_per(unit) | Projected rate per :second, :minute, or :hour |
#busy?(threshold:, unit: :second) | True when current rate exceeds threshold for the given unit |
#peak_rate | Highest rate per second observed since creation or last reset |
#snapshot | Frozen hash with count, rate, peak_rate, window, and timestamp |
#time_since_last | Seconds since the most recent increment, or nil if the window is empty |
#reset | Clear all recorded events |
Philiprehberger::RateCounter::Registry| Method | Description |
|---|---|
.new(window:) | Create a registry with a default window for new counters |
#[](name) | Access or create a named counter |
#names | List all registered counter names |
#size | Number of registered counters |
#snapshot | Frozen hash of name to counter snapshot |
#reset_all | Reset all counters |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: