-
-
Notifications
You must be signed in to change notification settings - Fork 138
Add Discord rate limiting with exponential backoff and Redis coordination (#284) #288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| Discord Rate Limiting System | ||
| Overview | ||
|
|
||
| This implementation adds robust Discord API rate limit handling with: | ||
|
|
||
| Automatic 429 detection | ||
|
|
||
| Exponential backoff retry logic (2^n + jitter) | ||
|
|
||
| Configurable maximum retry attempts (default: 3) | ||
|
|
||
| Redis-based distributed rate limit tracking | ||
|
|
||
| Per-channel bucket isolation | ||
|
|
||
| Command queueing using per-channel asyncio locks | ||
|
|
||
| Minimal performance overhead when not rate limited | ||
|
|
||
| This ensures improved bot resilience and production readiness. | ||
|
|
||
| Architecture | ||
|
|
||
| Flow: | ||
|
|
||
| User Message | ||
| β DiscordBot | ||
| β Per-channel Lock (Queueing) | ||
| β DiscordRateLimiter | ||
| β Redis (Bucket Tracking) | ||
| β Discord API | ||
|
|
||
| Retry Mechanism | ||
|
|
||
| When a 429 HTTPException occurs: | ||
|
|
||
| Extract retry_after from Discord response | ||
|
|
||
| Store reset timestamp in Redis: | ||
|
|
||
| discord_ratelimit:<channel_id> | ||
|
|
||
| Calculate exponential backoff: | ||
|
|
||
| delay = (2^attempt Γ retry_after) + jitter | ||
|
|
||
| Retry up to max_retries times (default = 3) | ||
|
|
||
| If retries are exhausted, an exception is raised. | ||
|
|
||
| Distributed Rate Limit Tracking | ||
|
|
||
| Redis is used to coordinate rate limits across multiple bot instances. | ||
|
|
||
| Key format: | ||
|
|
||
| discord_ratelimit:<bucket> | ||
|
|
||
| Where: | ||
|
|
||
| bucket = Discord channel ID | ||
|
|
||
| This ensures: | ||
|
|
||
| Only the affected channel waits | ||
|
|
||
| Other channels continue operating normally | ||
|
|
||
| Safe multi-instance deployments | ||
|
|
||
| Command Queueing | ||
|
|
||
| Per-channel asyncio.Lock ensures: | ||
|
|
||
| Sequential message processing per channel | ||
|
|
||
| No concurrent retry storms | ||
|
|
||
| Clean isolation of channel traffic | ||
|
|
||
| This acts as a lightweight queue system. | ||
|
|
||
| Performance Characteristics | ||
|
|
||
| When NOT rate limited: | ||
|
|
||
| Single Redis GET | ||
|
|
||
| No artificial sleep | ||
|
|
||
| Direct execution | ||
|
|
||
| Negligible overhead (<1ms) | ||
|
|
||
| When rate limited: | ||
|
|
||
| Controlled exponential backoff | ||
|
|
||
| Shared distributed coordination via Redis | ||
|
|
||
| Configuration | ||
|
|
||
| Environment variable required: | ||
|
|
||
| REDIS_URL=redis://localhost:6379 | ||
|
|
||
| Ensure Redis service is running before starting the bot. | ||
|
|
||
| Testing | ||
|
|
||
| Unit tests cover: | ||
|
|
||
| Successful execution without rate limit | ||
|
|
||
| Retry behavior on 429 | ||
|
|
||
| Exponential backoff growth | ||
|
|
||
| Maximum retry exhaustion | ||
|
|
||
| Redis key storage on 429 | ||
|
|
||
| Delay enforcement | ||
|
|
||
| Run tests: | ||
|
|
||
| pytest tests/test_rate_limiter.py | ||
|
|
||
| Future Improvements | ||
|
|
||
| Per-endpoint bucket parsing from Discord headers | ||
|
|
||
| Prometheus metrics integration | ||
|
|
||
| Advanced distributed worker queue | ||
|
|
||
| Rate limit analytics dashboard | ||
|
|
||
| Issue Reference | ||
|
|
||
| Implements Issue #284 | ||
|
|
||
| Adds production-grade Discord rate limiting with exponential backoff and distributed coordination. | ||
|
Comment on lines
+1
to
+143
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion | π Major The file contains no Markdown formatting and will render as an unstructured wall of plain text. Despite the π Proposed Markdown rewrite-Discord Rate Limiting System
-Overview
+# Discord Rate Limiting System
+
+## Overview
-This implementation adds robust Discord API rate limit handling with:
+This implementation adds robust Discord API rate-limit handling with:
-Automatic 429 detection
-Exponential backoff retry logic (2^n + jitter)
-Configurable maximum retry attempts (default: 3)
-Redis-based distributed rate limit tracking
-Per-channel bucket isolation
-Command queueing using per-channel asyncio locks
-Minimal performance overhead when not rate limited
+- Automatic 429 detection
+- Exponential backoff retry logic (`2^attempt Γ retry_after + jitter`)
+- Configurable maximum retry attempts (default: 3)
+- Redis-based distributed rate-limit tracking
+- Per-channel bucket isolation
+- Command queueing using per-channel asyncio locks
+- Minimal performance overhead when not rate limited
-This ensures improved bot resilience and production readiness.
+This ensures improved bot resilience and production readiness.
-Architecture
+## Architecture
-Flow:
+### Flow
-User Message
-β DiscordBot
-β Per-channel Lock (Queueing)
-β DiscordRateLimiter
-β Redis (Bucket Tracking)
-β Discord API
+```
+User Message
+β DiscordBot
+β Per-channel Lock (Queueing)
+β DiscordRateLimiter
+β Redis (Bucket Tracking)
+β Discord API
+```
-Retry Mechanism
+## Retry Mechanism
-When a 429 HTTPException occurs:
+When a 429 `HTTPException` occurs:
-Extract retry_after from Discord response
-Store reset timestamp in Redis:
-discord_ratelimit:<channel_id>
-Calculate exponential backoff:
-delay = (2^attempt Γ retry_after) + jitter
-Retry up to max_retries times (default = 3)
-If retries are exhausted, an exception is raised.
+1. Extract `retry_after` from the Discord response.
+2. Store the reset timestamp in Redis under key `discord_ratelimit:<channel_id>`.
+3. Calculate exponential backoff: `delay = (2^attempt Γ retry_after) + jitter`
+4. Retry up to `max_retries` times (default: 3).
+5. If retries are exhausted, raise an exception.
-Distributed Rate Limit Tracking
+## Distributed Rate Limit Tracking
-Redis is used to coordinate rate limits across multiple bot instances.
+Redis coordinates rate limits across multiple bot instances.
-Key format:
-discord_ratelimit:<bucket>
+**Key format:** `discord_ratelimit:<bucket>`
-Where:
-bucket = Discord channel ID
+Where `bucket` = Discord channel ID.
-This ensures:
-Only the affected channel waits
-Other channels continue operating normally
-Safe multi-instance deployments
+This ensures:
+- Only the affected channel waits.
+- Other channels continue operating normally.
+- Safe multi-instance deployments.
-Command Queueing
+## Command Queueing
-Per-channel asyncio.Lock ensures:
-Sequential message processing per channel
-No concurrent retry storms
-Clean isolation of channel traffic
+Per-channel `asyncio.Lock` ensures:
+- Sequential message processing per channel.
+- No concurrent retry storms.
+- Clean isolation of channel traffic.
-This acts as a lightweight queue system.
+This acts as a lightweight queue system.
-Performance Characteristics
+## Performance Characteristics
-When NOT rate limited:
-Single Redis GET
-No artificial sleep
-Direct execution
-Negligible overhead (<1ms)
+**When NOT rate limited:**
+- Single Redis `GET`
+- No artificial sleep
+- Direct execution
+- Negligible overhead (<1 ms)
-When rate limited:
-Controlled exponential backoff
-Shared distributed coordination via Redis
+**When rate limited:**
+- Controlled exponential backoff
+- Shared distributed coordination via Redis
-Configuration
+## Configuration
-Environment variable required:
-REDIS_URL=redis://localhost:6379
+Environment variable required:
-Ensure Redis service is running before starting the bot.
+```env
+REDIS_URL=redis://localhost:6379
+```
-Testing
+Ensure Redis is running before starting the bot.
-Unit tests cover:
-Successful execution without rate limit
-Retry behavior on 429
-Exponential backoff growth
-Maximum retry exhaustion
-Redis key storage on 429
-Delay enforcement
+## Testing
-Run tests:
-pytest tests/test_rate_limiter.py
+Unit tests cover:
+- Successful execution without rate limit
+- Retry behavior on 429
+- Exponential backoff growth
+- Maximum retry exhaustion
+- Redis key storage on 429
+- Delay enforcement
-Future Improvements
-Per-endpoint bucket parsing from Discord headers
-Prometheus metrics integration
-Advanced distributed worker queue
-Rate limit analytics dashboard
+Run tests:
-Issue Reference
-Implements Issue `#284`
-Adds production-grade Discord rate limiting with exponential backoff and distributed coordination.
+```bash
+pytest tests/test_rate_limiter.py
+```
+
+## Future Improvements
+
+- Per-endpoint bucket parsing from Discord headers
+- Prometheus metrics integration
+- Advanced distributed worker queue
+- Rate limit analytics dashboard
+
+## Issue Reference
+
+Implements [Issue `#284`](../../issues/284) β adds production-grade Discord rate limiting with exponential backoff and distributed coordination.π§° Toolsπͺ LanguageTool[uncategorized] ~1-~1: If this is a compound adjective that modifies the following noun, use a hyphen. (EN_COMPOUND_ADJECTIVE_INTERNAL) π€ Prompt for AI Agents |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 93
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 642
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 44
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 44
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 165
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 170
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 3322
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 845
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 91
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 44
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 128
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 132
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 953
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 800
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 2835
π Script executed:
Repository: AOSSIE-Org/Devr.AI
Length of output: 44
Align the two formula descriptions in the overview and retry mechanism sections.
Line 8 describes the algorithm as
2^n + jitter, while Line 45 describes it asdelay = (2^attempt Γ retry_after) + jitter. These are mathematically distinct formulas. Clarify which formula is intended and update both sections to be consistent. Note: The referencedrate_limiter.pyimplementation does not currently exist in the repository, so alignment should be based on the intended design for this feature.π€ Prompt for AI Agents