Skip to content

fix(datasets): isolate filter state to fix concurrent /dataset race#39685

Merged
rusackas merged 2 commits into
masterfrom
ce/task-10
May 21, 2026
Merged

fix(datasets): isolate filter state to fix concurrent /dataset race#39685
rusackas merged 2 commits into
masterfrom
ce/task-10

Conversation

@rusackas
Copy link
Copy Markdown
Member

Summary

Adopts #33895 (thanks @MIKEX818!) with the requested cleanups and a regression test.

DatasetRestApi now overrides _handle_filters_args so each request builds a fresh Filters instance. The Flask-AppBuilder default mutates a single self._filters shared across requests, which under concurrent traffic leaks filter state from one request into another — observed in #33828 as GET /api/v1/dataset/?q=(filters:!((col:table_name,opr:eq,value:...))) returning the wrong dataset roughly 5% of the time when ~12 parallel calls fan out.

Returning a request-scoped Filters keeps each call isolated.

Changes vs. #33895

Addresses review feedback from @hainenber and @sadpandajoe:

  • Drop unused import copy.
  • Drop the duplicate from typing import Any, Callable, Dict line; use modern dict[str, Any] annotation instead.
  • Pull API_FILTERS_RIS_KEY into the existing FAB-const import block.
  • Clean up the docstring (the original had garbled paste artifacts and a dead # self._filters.clear_filters() comment) and explicitly note this overrides the FAB method (clarifying the question @sadpandajoe raised).
  • Add a unit test (test_handle_filters_args_returns_request_scoped_filters) that asserts a fresh Filters instance is constructed per call — the property that prevents the race.

Re: @Vitor-Avila's question about whether this should live in FAB instead — that's a reasonable position, but FAB hasn't responded since June 2025 and Superset users are hitting this in production. Patching here unblocks 5.x; FAB can absorb it later.

Before / After

Before: parallel GET /api/v1/dataset/ filtered by different table_name values intermittently returns mismatched datasets.
After: each request's filter state is isolated; the race window is closed.

Testing instructions

  • pytest tests/unit_tests/datasets/api_tests.py::test_handle_filters_args_returns_request_scoped_filters passes.
  • Reproduce from Intermittent Dataset Retrieval Errors When Making Parallel API Requests #33828: fire ~12 concurrent GET /api/v1/dataset/?q=(filters:!((col:table_name,opr:eq,value:<unique>))) requests with distinct table_name values; each response should match its query's table_name 100% of the time.

Additional information

🤖 Generated with Claude Code via Custodial Engineer task #10

Override _handle_filters_args on DatasetRestApi to build a fresh
Filters instance per request. The FAB default mutates a single
self._filters shared across requests, which under concurrent traffic
leaks filters from one request into another (#33828).

Adopts #33895 with review-comment cleanups (drop unused imports, fix
docstring) and adds a regression test.

Co-Authored-By: Michelle <MIKEX818>
@bito-code-review
Copy link
Copy Markdown
Contributor

bito-code-review Bot commented Apr 27, 2026

Code Review Agent Run #afaa7b

Actionable Suggestions - 0
Review Details
  • Files reviewed - 2 · Commit Range: b03642d..b03642d
    • superset/datasets/api.py
    • tests/unit_tests/datasets/api_tests.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@dosubot dosubot Bot added api Related to the REST API change:backend Requires changing the backend labels Apr 27, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 63.83%. Comparing base (b791f4c) to head (862b193).
⚠️ Report is 388 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #39685      +/-   ##
==========================================
- Coverage   64.48%   63.83%   -0.65%     
==========================================
  Files        2566     2585      +19     
  Lines      133926   136973    +3047     
  Branches    31096    31519     +423     
==========================================
+ Hits        86357    87434    +1077     
- Misses      46074    48007    +1933     
- Partials     1495     1532      +37     
Flag Coverage Δ
hive 39.41% <100.00%> (-0.36%) ⬇️
mysql 59.06% <100.00%> (-1.16%) ⬇️
postgres 59.14% <100.00%> (-1.16%) ⬇️
presto 41.10% <100.00%> (-0.45%) ⬇️
python 60.57% <100.00%> (-1.30%) ⬇️
sqlite 58.78% <100.00%> (-1.15%) ⬇️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rusackas
Copy link
Copy Markdown
Member Author

@betodealmeida @michael-s-molina @sadpandajoe — gentle ping on this one: CI is green and there are no open review threads. Let me know if any of you happen to have bandwidth to take a look :)

@rusackas rusackas requested a review from aminghadersohi May 20, 2026 20:52
Copy link
Copy Markdown
Contributor

@aminghadersohi aminghadersohi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean fix for the FAB shared-filter race condition. Implementation is minimal and correct — three lines that construct a fresh Filters per call, add request-scoped filters, and return the joined result without touching self._filters. Docstring is exemplary: names the overridden method, explains the shared-state mechanism, gives a concrete failure example, and states the fix invariant. Regression test directly verifies the fresh-instance-per-call contract.

One medium-priority observation worth a follow-up: the same FAB _handle_filters_args race exists in all other BaseSupersetModelRestApi subclasses (ChartRestApi, DashboardRestApi, SavedQueryRestApi, QueryRestApi, etc.). Scoping the override to DatasetRestApi fixes the reported issue but leaves the others unprotected. Worth either moving the fix to BaseSupersetModelRestApi in base_api.py or opening a tracking issue for the remaining subclasses.

Not a blocker — the targeted fix is valid and the PR ships cleanly as-is.

Per reviewer feedback on #39685: the FAB `_handle_filters_args` race
that this PR addressed for `DatasetRestApi` exists in every other
subclass too (ChartRestApi, DashboardRestApi, SavedQueryRestApi,
QueryRestApi, DatabaseRestApi, etc.) — they all inherit from FAB's
`ModelRestApi`, which mutates a single shared `self._filters` instance
across requests.

Move the override from `DatasetRestApi` to `BaseSupersetModelRestApi`
so all subclasses inherit the request-scoped behavior. The override is
purely generic — no dataset-specific logic — and no other superset
REST API overrides `_handle_filters_args` (checked), so there's zero
collision risk. `BaseSupersetModelRestApi` is documented as the place
to "implement specific superset generic functionality", so wrapping
FAB behavior we want to differ from upstream is exactly its purpose.

Test stays in `tests/unit_tests/datasets/api_tests.py` using
`DatasetRestApi` as a concrete subclass to exercise the inherited
behavior; docstring updated to note the broader scope.
@rusackas
Copy link
Copy Markdown
Member Author

Done in 862b193. Lifted _handle_filters_args from DatasetRestApi to BaseSupersetModelRestApi (superset/views/base_api.py), so the request-scoped fix now applies to every subclass — ChartRestApi, DashboardRestApi, SavedQueryRestApi, QueryRestApi, DatabaseRestApi, etc. — not just datasets.

The override is purely generic (no dataset-specific logic), and a grep confirmed no other superset REST API overrides _handle_filters_args, so zero collision risk. Docstring updated to reference the broader scope and cite #33828 for the original dataset-level repro. Test stays in tests/unit_tests/datasets/api_tests.py using DatasetRestApi as a concrete subclass to exercise the inherited behavior.

Thanks for the catch — this would've been a follow-up that nobody got to.

@github-actions github-actions Bot removed the api Related to the REST API label May 20, 2026
@netlify
Copy link
Copy Markdown

netlify Bot commented May 20, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit 862b193
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a0e3a82c0966300086a6fff
😎 Deploy Preview https://deploy-preview-39685--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@rusackas rusackas merged commit 73f66e4 into master May 21, 2026
78 of 79 checks passed
@rusackas rusackas deleted the ce/task-10 branch May 21, 2026 18:12
@bito-code-review
Copy link
Copy Markdown
Contributor

Bito Automatic Review Skipped – PR Already Merged

Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.
No action is needed if you didn't intend to review it. To get a review, you can type /review in a comment and save it

sha174n pushed a commit to sha174n/superset that referenced this pull request May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Intermittent Dataset Retrieval Errors When Making Parallel API Requests

3 participants