-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem or Use Case
Currently, rate limits are static - once defined, they remain constant until manually updated via set_limits(). Real-world scenarios often require limits that vary based on:
- Time of day - Lower limits during peak hours to protect backend systems
- Day of week - Different limits for weekdays vs weekends
- Calendar events - Special limits during known high-traffic periods (Black Friday, product launches)
- Maintenance windows - Reduced limits during deployments
Users must currently implement their own scheduling logic and call set_limits() at appropriate times, which is error-prone and requires external orchestration.
Proposed Solution
Add schedule support to the Limit model that allows defining time-based variations:
from zae_limiter import Limit, Schedule, ScheduleOverride
# Option 1: Schedule as separate object
schedule = Schedule(
default=Limit.per_minute("rpm", capacity=1000),
overrides=[
ScheduleOverride(
cron="0 9-17 * * MON-FRI", # 9 AM - 5 PM weekdays
limit=Limit.per_minute("rpm", capacity=500),
),
ScheduleOverride(
cron="0 0-6 * * *", # Midnight to 6 AM daily
limit=Limit.per_minute("rpm", capacity=2000), # Higher off-peak
),
],
)
# Option 2: Inline on Limit (simpler API)
Limit.per_minute(
"rpm",
capacity=1000,
schedules=[
{"cron": "0 9-17 * * MON-FRI", "capacity": 500}, # Peak hours
],
)Key Design Decisions
- Cron syntax - Use standard 5-field cron for familiarity
- Resolution at acquire-time - Evaluate schedule when
acquire()is called - Override precedence - First matching schedule wins, or most specific
- Immutability preserved -
Limitremains frozen;Schedulewraps multipleLimitinstances
Schema Impact
Option A: No schema change - Resolve schedules client-side
- Schedules stored as JSON in limit config
- RateLimiter evaluates schedule on
acquire() - ✅ No migration needed
- ❌ All clients must upgrade to honor schedules
Option B: Server-side resolution - Add Lambda schedule evaluator
- Aggregator Lambda evaluates schedules
- Stores "effective limits" that change over time
- ✅ Works for all client versions
- ❌ More complex, higher Lambda invocation cost
Success Criteria
- Define schedules at System/Resource/Entity levels
- Schedules resolve correctly at acquire-time
- Audit logs capture which schedule was active
- CLI can display current effective limits with schedule info
- Documentation covers common scheduling patterns
Alternatives Considered
-
External scheduler - Use CloudWatch Events or Step Functions to call
set_limits()on schedule. Rejected: Adds operational complexity, no atomicity. -
Database TTL-based - Store future limit values with activation timestamps. Rejected: DynamoDB TTL is for deletion, not activation.
-
Webhook-based - External service pushes limits. This is tracked as a separate feature for event-driven updates.
Open Questions
The following should be discussed in comments before implementation:
Timezone Handling
- UTC-only (simpler)?
- Per-schedule timezone support?
- Entity-level timezone configuration?
Schedule Inheritance
- Should entity schedules override or merge with resource/system schedules?
- Example: System has peak-hours schedule, entity has weekend schedule - how do they combine?
Related Work
- Centralized Configuration (ADR-001) provides the hierarchy for schedule inheritance
- Usage snapshots could correlate with schedule changes for analysis
- Part of the Dynamic Rate Limits initiative (see related issues)