Optimize broker queue fetching with Redis pipelining, TTL cache, and pagination#1493
Open
ShubhAtWork wants to merge 1 commit intomher:masterfrom
Open
Optimize broker queue fetching with Redis pipelining, TTL cache, and pagination#1493ShubhAtWork wants to merge 1 commit intomher:masterfrom
ShubhAtWork wants to merge 1 commit intomher:masterfrom
Conversation
…pagination With 10,000+ queues, the existing `RedisBase.queues()` issues one `LLEN` command per priority step per queue sequentially. With the default 4 priority steps, that's 40,000 individual Redis round-trips per page load — taking 30-60 seconds and creating severe latency. Additionally, every page load or API call re-fetches all queue lengths from scratch, and the `/api/queues/length` endpoint returns all queues with no pagination, making it impractical for large deployments. Changes: 1. **Redis pipelining**: Batch all LLEN commands into a single Redis pipeline (non-transactional). For 10,000 queues with 4 priority steps, this reduces 40,000 round-trips to 1 (or a few if chunking kicks in). Measured improvement: 30-60s -> <1s. 2. **Pipeline chunking**: Pipelines are split into chunks of 5,000 commands to avoid overwhelming Redis with a single 40k-command pipeline. This prevents Redis from blocking other clients during execution. 3. **TTL cache**: Queue stats are cached in memory with a configurable TTL (default 5s, `--queue_cache_ttl`). Multiple concurrent requests within the TTL window share the same result, reducing redundant broker round-trips. 4. **Pagination**: `/api/queues/length` now supports `limit` and `offset` query parameters with a `total` field in the response, allowing clients to paginate through large queue lists. 5. **`RedisBase.close()`**: Properly close Redis connections when the broker client is no longer needed. Previously, Redis connections created per-request in views were never closed. 6. **RabbitMQ frozenset filter**: Use `frozenset(names)` instead of a list for O(1) membership testing when filtering RabbitMQ API responses. Also increased RabbitMQ API timeouts from 1s/2s to 5s/30s to handle large deployments. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With 10,000+ queues, the existing
RedisBase.queues()issues oneLLENcommand per priority step per queue sequentially. With the default 4 priority steps, that's 40,000 individual Redis round-trips per page load — taking 30-60 seconds and creating severe latency on the Broker view and/api/queues/lengthendpoint.Additionally, every page load re-fetches all queue lengths from scratch, and the API endpoint returns all queues with no pagination.
Changes
1. Redis pipelining
Batch all LLEN commands into a single Redis pipeline (non-transactional). For 10,000 queues with 4 priority steps, this reduces 40,000 round-trips to 1. Measured improvement: 30-60s -> <1s.
2. Pipeline chunking
Split pipelines into chunks of 5,000 commands to prevent Redis from blocking other clients during execution of a single massive pipeline.
3. TTL cache (
--queue_cache_ttl)Cache queue stats in memory with a configurable TTL (default 5s). Multiple concurrent requests within the TTL window share the same result. Set to 0 to disable.
4. Pagination for
/api/queues/lengthNew
limitandoffsetquery parameters, with atotalfield in the response.limit=0returns an empty list (consistent semantics), negative values return 400.5.
RedisBase.close()Properly close Redis connections when the broker client is no longer needed. Previously, Redis connections created per-request in views were never closed.
6. RabbitMQ optimizations
frozenset(names)for O(1) membership testing when filtering API responses (was O(n) list scan)http_client.close()in thefinallyblock (Tornado'sAsyncHTTPClientis shared/singleton)Test plan
pytest tests/unit/utils/test_broker_queues.py tests/unit/test_app.py— 15 tests pass/api/queues/length?limit=10&offset=0returns paginated results withtotal--queue_cache_ttl=0disables caching🤖 Generated with Claude Code