feat(datasource): add opt-in per-datasource query rate limit - #43
Open
devin-ai-integration[bot] wants to merge 1 commit into
Open
devin-ai-integration[bot] wants to merge 1 commit into
devin-ai-integration[bot] wants to merge 1 commit into
Conversation
Adds an opt-in, fixed-window rate limit on physical datasource queries, enforced in ExploreMixin.query(). Disabled by default. Co-Authored-By: patrick.bradley <patrick.bradley@cognition.ai>
Author
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
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
Adds an opt-in, per-datasource query rate limit. When enabled, at most
max_queriesphysical queries are executed against a single datasource perperiod_secondswindow, across all users; the request that exceeds the budget fails with HTTP 429 (DATASOURCE_QUERY_RATE_LIMIT_ERROR, issue code 1042).Disabled by default, so existing behavior and existing tests are untouched.
Enforcement point:
ExploreMixin.query()(superset/models/helpers.py)This is the single unified point where any explorable datasource (
SqlaTable, SQL-LabQuery) turns a query object into SQL and hits the analytics database. Every consumer funnels through it —/api/v1/chart/datasync and Celery/async, dashboards, drill-by, samples, thumbnails, alerts & reports — so the limit can't be bypassed by a new API surface, and it counts physical database queries rather than HTTP requests: results served from the query cache inQueryContextProcessor.get_df_payload()correctly don't consume budget, since they never reach the database.Rejected alternatives
ChartDataCommand.validate()/ the chart data API layer — runs before the cache lookup, so cache hits would be billed as queries, and it only covers chart data: SQL Lab, thumbnails, alerts and samples would bypass it entirely.QueryContextProcessor.get_df_payload()— correct with respect to caching, but still chart-data-only; thumbnails, reports and other datasource consumers don't go through a query context.Database.get_df()/ the engine spec layer — no datasource identity is available at that depth (only a SQL string and a database), and it would also throttle unrelated traffic such as metadata introspection and SQL Lab autocomplete.The counter is a fixed-window counter in the general-purpose cache (
CACHE_CONFIG), keyeddatasource-query-rate-limit:{uid}:{window}with TTL = window; a shared backend such as Redis is required for the limit to apply across workers. It is read and written without a lock, so under high concurrency the effective limit can slightly exceed the configured one — acceptable for protecting an analytics database from runaway load, and documented in the module docstring.TESTING INSTRUCTIONS
Covers the allowed path (calls under the budget pass and increment the counter), the throttled path (the call over the budget raises a 429
SupersetRateLimitExceededExceptionand never reachesdatabase.get_df()), per-datasource isolation of budgets, and the disabled-by-default no-op.Manually: set
DATASOURCE_QUERY_RATE_LIMIT = {"enabled": True, "max_queries": 2, "period_seconds": 60}insuperset_config.py, then load a chart withforce=truethree times within a minute — the third returns 429 with "Query rate limit exceeded for this datasource".ADDITIONAL INFORMATION
Devin-Org: engineering
Link to Devin session: https://app.devin.ai/sessions/e67c29adf6ca4c43bc669e4baeee3a58
Open in Devin Desktop: https://app.devin.ai/desktop/session/e67c29adf6ca4c43bc669e4baeee3a58?variant=devin
Requested by: @patrickbradley-cog