Outbound rate limiting
Sliding-window rate limit per destination phone number using a Redis sorted set. Alert-only by default; flip to blocking when confident.
Before every outbound call Breeze Buddy checks how many times it has dialed the same destination in a rolling window. If the count exceeds the limit it either sends a Slack alert or blocks the call, depending on config. The limiter is Redis-backed and atomic — no race conditions under concurrent load.
Prerequisites
- Redis reachable from the application (
REDIS_HOST,REDIS_PORT). - Optional: Slack webhook for alerts (
SLACK_WEBHOOK_URL). - Outbound calling enabled — see Call execution configuration.
How it works
For each destination phone number, Breeze Buddy maintains a Redis sorted set with {timestamp}:{lead_id} members scored by timestamp. An atomic Lua script runs before each call:
- Trims entries older than
now - window_seconds. - Counts remaining calls.
- Records the current call.
- Returns the pre-insert count.
If count >= max_calls, the limit is tripped.
Key settings
| Env var | Default | Controls |
|---|---|---|
OUTBOUND_RATE_LIMIT_MAX_CALLS | 7 | Maximum calls per destination in the window. |
OUTBOUND_RATE_LIMIT_WINDOW_SECONDS | 3600 | Rolling window length in seconds. |
OUTBOUND_RATE_LIMIT_BLOCK_ENABLED | false | true blocks the call. false sends an alert and lets the call proceed. |
Example config
OUTBOUND_RATE_LIMIT_MAX_CALLS=7
OUTBOUND_RATE_LIMIT_WINDOW_SECONDS=3600
OUTBOUND_RATE_LIMIT_BLOCK_ENABLED=false
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/xxxStart in alert-only mode. Watch the Slack channel for a week or two to confirm the limit isn’t too aggressive, then flip OUTBOUND_RATE_LIMIT_BLOCK_ENABLED=true.
Operational notes
- Atomicity — the Lua script guarantees atomicity. Even under high concurrency on the same destination, every call sees a consistent count.
- Redis unavailable — the check is skipped fail-open. The call proceeds and is logged for audit. Redis outage will not halt outbound calling.
- TTL self-cleanup — keys auto-extend their TTL on activity and auto-delete when a number stops being called. No manual cleanup.
- Blocked calls — when blocking is enabled, the lead is released back to the queue; you can retry or cancel via the Leads API.
- Noisy numbers — the limit is per destination, not per merchant. If your workload legitimately calls the same number repeatedly (e.g., warm-up tests), exclude those numbers in a separate channel.
Separate from telephony-provider rate limits
This limit is enforced by Breeze Buddy before the provider is called. Provider-side rate limits (Twilio account-level, Plivo app-level) are independent and may still fire.