Skip to content

fix(matrixify): handle async (202) chart-data responses in Matrixify grid cells#42033

Closed
jenwitteng wants to merge 3 commits into
apache:masterfrom
jenwitteng:upstream-async-202-squashed
Closed

fix(matrixify): handle async (202) chart-data responses in Matrixify grid cells#42033
jenwitteng wants to merge 3 commits into
apache:masterfrom
jenwitteng:upstream-async-202-squashed

Conversation

@jenwitteng

@jenwitteng jenwitteng commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

SUMMARY

With GLOBAL_ASYNC_QUERIES enabled, uncached chart-data requests return HTTP 202 with job metadata (channel_id, job_id, result_url) rather than inline results. Every Matrixify grid cell renders through StatefulChart (@superset-ui/core), which previously treated that 202 body as chart data — so each cell showed "No data" until a manual refresh warmed the cache.

StatefulChart now detects a 202 and delegates to an injected handleAsyncChartData hook, which polls the async event channel and resolves the cached results. The handler is wired in from ChartRenderer (reusing the existing handleChartDataResponse / waitForAsyncData) and flows through the standard hooks chain, keeping superset-ui-core decoupled from app-level async-event middleware. If a 202 arrives with no handler, StatefulChart fails loudly instead of silently rendering empty data.

Because a matrix fires many concurrent per-cell requests that can be superseded by filter/formData changes and unmounted by scrolling, the change also hardens the async lifecycle:

  • Correct response shapes — the legacy endpoint's flat 202 body is wrapped as { result: [body] } to match the V1 signature the async handler expects (legacy async previously received undefined); V1 bodies pass through unchanged.
  • Supersession guards — each request captures its own AbortController; a late sync/async result or error is discarded if a newer request has superseded it, so stale data can't overwrite fresh chart data.
  • Cancellation & no leakswaitForAsyncData accepts an AbortSignal, removes its event listener on abort/unmount (no leaked listeners keeping the poller busy), and cancels the in-flight cached-result download when aborted mid-fetch.
  • Latest props on refetchfetchData reads current props via a ref (it's memoized with an empty dep list), so updated filters/formData are used on refetch.
  • Render-only changes preserved — resolving an older async request renders with the latest formData, so color/zoom changes aren't reverted.
  • Detailed error messages — array-shaped waitForAsyncData rejections are unwrapped so the parsed client-error message survives instead of collapsing to a generic "An error occurred".

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

BEFORE: Matrixify cells show "No data" on first load when cache is cold.
Screenshot 2569-07-14 at 10 54 37

AFTER: Cells show loading state, then resolve and render charts without requiring a manual refresh.
Screenshot 2569-07-14 at 10 57 31

TESTING INSTRUCTIONS

  1. Enable GLOBAL_ASYNC_QUERIES (and its required Celery worker + cache/results backend + websocket/polling config)
  2. Open a dashboard containing a Matrixify chart whose per-cell queries are not already cached (clear cache or use force)
  3. Verify cells show a loading state, then resolve and render each chart on first load (not "No data")
  4. Verify a legacy-API viz (e.g. deck.gl / world map / country map) in a matrix cell also resolves
  5. Rapidly change a dashboard filter while cells are still resolving — confirm cells settle on the latest filter's data (no stale overwrite) and no console errors/leaked listeners
  6. Scroll a large matrix so cells unmount mid-load — confirm no "setState on unmounted component" warnings and pending downloads are cancelled
  7. Run automated tests:
    cd superset-frontend
    npm run test -- StatefulChart.test.tsx
    npm run test -- asyncEvent.test.ts

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags: GLOBAL_ASYNC_QUERIES (behavior only differs when enabled; unchanged when off)
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

@dosubot dosubot Bot added change:frontend Requires changing the frontend global:async-query Related to Async Queries feature viz:charts Namespace | Anything related to viz types labels Jul 14, 2026
@bito-code-review

bito-code-review Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #00a593

Actionable Suggestions - 0
Additional Suggestions - 4
  • superset-frontend/src/middleware/asyncEvent.ts - 2
    • CWE-1321: Prototype Pollution via Record · Line 66-67
      Replacing Map with Record removes the prototype chain protection that the original code's comments explicitly documented. The `job_id` originates from server/WebSocket payloads which may be attacker-controlled. Use `Map.has()` and `Map.get()` instead of bracket notation to prevent prototype pollution. ([CWE-1321](https://cwe.mitre.org/data/definitions/1321.html))
    • CWE-1321: Listener Call Without Type Validation · Line 187-189
      Removed the function-type check that prevented calling non-function values stored in listenersByJobId. Combined with prototype chain exposure from Record, this could allow prototype-injected non-function values to be called, causing runtime errors or unexpected behavior. ([CWE-1321](https://cwe.mitre.org/data/definitions/1321.html))
  • superset-frontend/src/components/Chart/chartAction.ts - 1
    • Stale check inconsistent between paths · Line 845-850
      The stale failure guard (currentController !== controller check before dispatching chartUpdateFailed) was removed from lines 845-852 alongside the success-path stale check. The test at line 160 only covers success case — the error path also needs the same guard for consistency and to prevent stale failures from overwriting newer query error states.
  • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx - 1
    • Inconsistent API endpoint path · Line 303-303
      The endpoint `/superset/explore_json/` is pre-prefixed with appRoot, but SupersetClientClass strips this prefix before prepending appRoot again, making the pre-prefixing redundant and inconsistent with ChartClient (line 112 uses `/explore_json/`). Use `/explore_json/` without the appRoot prefix.
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset-frontend/src/components/Chart/chartAction.ts - 3
  • superset-frontend/src/middleware/asyncEvent.ts - 1
Review Details
  • Files reviewed - 7 · Commit Range: 949c255..949c255
    • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
    • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
    • superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts
    • superset-frontend/src/components/Chart/ChartRenderer.tsx
    • superset-frontend/src/components/Chart/chartAction.ts
    • superset-frontend/src/middleware/asyncEvent.test.ts
    • superset-frontend/src/middleware/asyncEvent.ts
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ 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


const addListener = (id: string, fn: ListenerFn) => {
listenersByJobId.set(id, fn);
const addListener = (id: string, fn: any) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: Replace the any parameter type with the existing listener function type so the listener contract is enforced at compile time. [custom_rule]

Severity Level: Minor 🧹

Why it matters? ⭐

The final TypeScript code still uses any in a changed line (fn: any), which directly violates the custom rule prohibiting any types in new or modified code. A concrete function type should be used instead.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 16)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/middleware/asyncEvent.ts
**Line:** 70:70
**Comment:**
	*Custom Rule: Replace the `any` parameter type with the existing listener function type so the listener contract is enforced at compile time.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The suggestion to replace any with ListenerFn in the addListener function is correct and improves type safety. You can resolve this by updating the parameter type in superset-frontend/src/middleware/asyncEvent.ts.

const addListener = (id: string, fn: ListenerFn) => {
  listenersByJobId[id] = fn;
};

I have implemented this change. Would you like me to check the rest of the comments on this PR and implement fixes for them as well?

superset-frontend/src/middleware/asyncEvent.ts

const addListener = (id: string, fn: ListenerFn) => {
  listenersByJobId[id] = fn;
};

@jenwitteng jenwitteng changed the title fix(charts): handle async (202) chart-data responses in StatefulChart fix(matrixify): handle async (202) chart-data responses in Matrixify grid cells Jul 14, 2026
Comment on lines +145 to +149
logging.warn('received event with status', asyncEvent.status);
// Non-terminal status: drop this (stale) job listener but keep the
// abort handler so an unmount/supersede can still reject the pending
// promise (full cleanup here would leave it hanging on abort).
removeListener(jobId);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: In the non-terminal status branch, the listener is removed immediately, so if a job emits pending/running before done, the subsequent terminal event has no listener and the waiting promise can hang forever. Keep the listener registered for non-terminal states and only clean it up on terminal states (done, error) or abort. [logic error]

Severity Level: Critical 🚨
❌ Async chart queries can hang waiting for results.
❌ Native filter values never resolve under async queries.
⚠️ Async event retries log noisy 'listener not found' warnings.
Steps of Reproduction ✅
1. Enable GLOBAL_ASYNC_QUERIES so async events middleware is active, as wired by `init()`
in `superset-frontend/src/middleware/asyncEvent.ts` (lines ~12-36) and the backend
`AsyncEventsRestApi.events` endpoint in `superset/async_events/api.py:35-41`.

2. Trigger a chart data request that returns HTTP 202 with async job metadata, which flows
into `handleChartDataResponse` in
`superset-frontend/src/components/Chart/chartAction.ts:17-45`; for status 202 it calls
`waitForAsyncData(result, signal)` to await async results.

3. For that job_id, let the backend emit a non-terminal async event (e.g. status "pending"
or "running") via `/api/v1/async_event/` so the frontend receives it and passes it to
`processEvents` in `superset-frontend/src/middleware/asyncEvent.ts:184-207`, which looks
up `listenersByJobId[jobId]` and invokes the listener created inside `waitForAsyncData`.

4. When the listener runs, `switch (asyncEvent.status)` in `asyncEvent.ts:12-41` hits the
`default` branch for the non-terminal status, logs the warning and calls
`removeListener(jobId)` (lines 145-149 in the PR hunk) without resolving or rejecting the
promise; subsequent terminal events (`status: "done"` or `"error"`) for the same job_id
are processed by `processEvents` but find no listener, fall into the retry/race-condition
branch, and ultimately log "listener not found for job_id" without ever settling the
original promise, leaving charts and native filters that relied on `waitForAsyncData`
stuck waiting indefinitely.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/middleware/asyncEvent.ts
**Line:** 145:149
**Comment:**
	*Logic Error: In the non-terminal status branch, the listener is removed immediately, so if a job emits `pending`/`running` before `done`, the subsequent terminal event has no listener and the waiting promise can hang forever. Keep the listener registered for non-terminal states and only clean it up on terminal states (`done`, `error`) or abort.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

bito-code-review Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #50dae7

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset-frontend/src/middleware/asyncEvent.ts - 1
Review Details
  • Files reviewed - 3 · Commit Range: 949c255..c1b17df
    • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
    • superset-frontend/src/components/Chart/chartAction.ts
    • superset-frontend/src/middleware/asyncEvent.ts
  • Files skipped - 0

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

@sadpandajoe
sadpandajoe requested review from msyavuz and rusackas July 16, 2026 17:10
jenwitteng and others added 3 commits July 17, 2026 13:01
When GLOBAL_ASYNC_QUERIES is enabled, uncached chart-data requests return
HTTP 202 with job metadata (channel_id, job_id, result_url) instead of
inline results. StatefulChart (used by chart components that fetch their
own data) previously treated this metadata as chart data, causing charts
to render "No data" until a refresh warmed the cache.

StatefulChart now:
- Detects HTTP 202 responses via the standardized async-query shape
  (channel_id + job_id + result_url)
- Delegates to an injected handleAsyncChartData hook (wired from
  ChartRenderer, reusing handleChartDataResponse / waitForAsyncData)
- Fails loudly if 202 arrives with no handler, instead of silently
  showing empty data
- Supports abort signals to cancel async waits mid-flight
- Cleans up event listeners properly to avoid stale-callback races

The handler flows through the existing hooks chain, keeping
superset-ui-core decoupled from app-level async-event middleware.

Additional improvements:
- asyncEvent: refine listener cleanup and stale-callback handling
- chartAction: support abort signal propagation for async downloads
- StatefulChart: harden lifecycle handling and supersession races
- Add comprehensive test coverage for async flows

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
…perset/ prefix

- Import ensureAppRoot from navigationUtils instead of pathUtils
- Use /explore_json/ instead of /superset/explore_json/ to match upstream convention
…status handling

- Replace any type with ListenerFn for type safety
- Fix critical bug: keep listener registered for non-terminal status events
  (pending, running) so they can receive terminal events (done, error)
- Previous code removed listener on non-terminal status, causing promises
  to hang forever when jobs emit status updates before completion
@jenwitteng
jenwitteng force-pushed the upstream-async-202-squashed branch from c1b17df to 3a92b01 Compare July 17, 2026 06:02
json: legacyBody,
});
// Force the legacy API path for this viz type
(getChartMetadataRegistry as any).mockReturnValue({

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: Replace the any cast with a concrete mock type (or unknown with a safe narrowing) to preserve type checking in this test. [custom_rule]

Severity Level: Minor 🧹

Why it matters? ⭐

The rule llmcfg-no-any-types forbids new or changed TypeScript code that uses any. This line explicitly casts getChartMetadataRegistry to any, so the violation is real and directly matches the rule.

Rule source 📖

.cursor/rules/dev-standard.mdc (line 16)

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
**Line:** 808:808
**Comment:**
	*Custom Rule: Replace the `any` cast with a concrete mock type (or `unknown` with a safe narrowing) to preserve type checking in this test.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +204 to 211
if (retriesByJobId[jobId] <= MAX_RETRIES) {
setTimeout(() => {
processEvents([asyncEvent]);
}, RETRY_DELAY * retries);
}, RETRY_DELAY * retriesByJobId[jobId]);
} else {
retriesByJobId.delete(jobId);
delete retriesByJobId[jobId];
logging.warn('listener not found for job_id', asyncEvent.job_id);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: The retry path drops an event permanently after MAX_RETRIES, but there is no fallback to deliver that terminal event when the listener is registered later. This can leave the corresponding async chart request hanging forever (no resolve/reject) if the event arrives before listener registration and registration is delayed (for example in heavy UI work or background-tab throttling). Keep unmatched terminal events in a per-job buffer and flush them from addListener, or explicitly fail pending jobs when retries are exhausted. [race condition]

Severity Level: Critical 🚨
❌ Charts using async queries can hang indefinitely awaiting events.
❌ Native filter controls may never load default async values.
⚠️ AsyncEvent tests don't cover listener-missing race drop behavior.
Steps of Reproduction ✅
1. Start the Superset frontend with the GlobalAsyncQueries feature flag enabled so the
async event middleware `init` runs (superset-frontend/src/middleware/asyncEvent.ts:34-60,
with `init();` at line 62 starting polling via `loadEventsFromApi` or WebSocket via
`wsConnect`).

2. Trigger a chart-data request that is handled by `exploreJSON` in
superset-frontend/src/components/Chart/chartAction.ts:734-942 (e.g., loading a chart or
dashboard), which eventually calls `handleChartDataResponse` (lines 700-752) and, when the
HTTP response status is 202, invokes `waitForAsyncData(...)` (lines 36-45 in the excerpt
at 680-759) with the async event payload.

3. In the async middleware, `waitForAsyncData`
(superset-frontend/src/middleware/asyncEvent.ts:107-171) calls `addListener(jobId,
listener)` (lines 78-80, 171) to register a listener in `listenersByJobId`. If an async
event for that job (status DONE or ERROR) is delivered by `loadEventsFromApi` (lines
226-246) before the listener is registered (due to network/UI delay or background tab
throttling), `loadEventsFromApi` still calls `fetchEvents(eventArgs)` and then
`processEvents(events)` (line 234).

4. Inside `processEvents` (superset-frontend/src/middleware/asyncEvent.ts:191-215), when
`listenersByJobId[jobId]` is undefined the else branch (lines 199-211) runs: it increments
`retriesByJobId[jobId]` (lines 201-202), schedules `processEvents([asyncEvent])` via
`setTimeout` (lines 204-207), and after more than `MAX_RETRIES` (line 59) deletes
`retriesByJobId[jobId]` and logs a warning (lines 208-210). The event is dropped
permanently while `setLastId(asyncEvent)` (line 213) advances `lastReceivedEventId`. When
`waitForAsyncData` is eventually called for that job from ChartAction.ts (lines 36-45),
FilterValue.tsx (lines 25-37), or FiltersConfigForm.tsx (lines 24-34), no further events
for that job ever reach the listener, so the Promise returned by `waitForAsyncData` never
resolves or rejects and the associated chart or filter stays stuck in a loading state.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/middleware/asyncEvent.ts
**Line:** 204:211
**Comment:**
	*Race Condition: The retry path drops an event permanently after `MAX_RETRIES`, but there is no fallback to deliver that terminal event when the listener is registered later. This can leave the corresponding async chart request hanging forever (no resolve/reject) if the event arrives before listener registration and registration is delayed (for example in heavy UI work or background-tab throttling). Keep unmatched terminal events in a per-job buffer and flush them from `addListener`, or explicitly fail pending jobs when retries are exhausted.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

const generation = pollingGeneration;
const eventArgs = lastReceivedEventId ? { last_id: lastReceivedEventId } : {};
if (listenersByJobId.size) {
if (Object.keys(listenersByJobId).length) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggestion: Conditionally skipping fetchEvents when there are no active listeners prevents lastReceivedEventId from advancing during idle periods, so the next active request can trigger a large backlog fetch and replay of stale events. That creates avoidable latency spikes and extra timer churn before current jobs are processed. Continue polling to advance lastReceivedEventId (even without listeners), and only gate listener dispatching. [performance]

Severity Level: Major ⚠️
⚠️ First async chart after idle can incur backlog delay.
⚠️ Async polling performs extra retries for stale unhandled events.
⚠️ Potential spikes in network and timer work on resume.
Steps of Reproduction ✅
1. On frontend startup, the async middleware `init`
(superset-frontend/src/middleware/asyncEvent.ts:34-60) is executed (line 62), loading
`lastReceivedEventId` from localStorage (lines 48-52) and starting polling via
`loadEventsFromApi` when `transport === TRANSPORT_POLLING` (lines 54-56).

2. While there are no active async chart jobs, `listenersByJobId` remains empty because
the only place that registers listeners is `waitForAsyncData` (asyncEvent.ts:107-171),
which is invoked from chart and native filter code when an HTTP 202 chart-data response is
received (ChartAction.ts:17-45 at 680-759, FilterValue.tsx:18-37 at 270-329,
FiltersConfigForm.tsx:15-35 at 520-579).

3. During this idle period, any async events emitted on the server-side for this user are
not fetched by the client because `loadEventsFromApi` (asyncEvent.ts:226-246) wraps the
call to `fetchEvents(eventArgs)` and subsequent `processEvents(events)` inside `if
(Object.keys(listenersByJobId).length) { ... }` (lines 229-240); with zero listeners, the
function returns after the guard and `lastReceivedEventId` (used in `eventArgs` at line
228) never advances.

4. When a new chart-data request later receives a 202 and registers a listener via
`waitForAsyncData`, the next invocation of `loadEventsFromApi` finally calls
`fetchEvents(eventArgs)` with a stale `lastReceivedEventId`. The backend returns the
backlog of all events since that cursor, and `processEvents(events)`
(asyncEvent.ts:191-215) iterates them: events for jobs without listeners go through the
retry loop (lines 199-211) before being dropped, and only then are current job events
processed. This creates an avoidable latency spike for the first active async chart and
extra `setTimeout` churn as stale events are retried and logged before the latest job’s
data is delivered.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** superset-frontend/src/middleware/asyncEvent.ts
**Line:** 229:240
**Comment:**
	*Performance: Conditionally skipping `fetchEvents` when there are no active listeners prevents `lastReceivedEventId` from advancing during idle periods, so the next active request can trigger a large backlog fetch and replay of stale events. That creates avoidable latency spikes and extra timer churn before current jobs are processed. Continue polling to advance `lastReceivedEventId` (even without listeners), and only gate listener dispatching.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

bito-code-review Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #49e034

Actionable Suggestions - 0
Review Details
  • Files reviewed - 7 · Commit Range: 8f48abb..3a92b01
    • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.test.tsx
    • superset-frontend/packages/superset-ui-core/src/chart/components/StatefulChart.tsx
    • superset-frontend/packages/superset-ui-core/src/chart/models/ChartProps.ts
    • superset-frontend/src/components/Chart/ChartRenderer.tsx
    • superset-frontend/src/components/Chart/chartAction.ts
    • superset-frontend/src/middleware/asyncEvent.test.ts
    • superset-frontend/src/middleware/asyncEvent.ts
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ 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

@jenwitteng jenwitteng closed this Jul 17, 2026
@jenwitteng

jenwitteng commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

i think i did create base on 6.1 and overwrite to master..
will try craete another pr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:frontend Requires changing the frontend global:async-query Related to Async Queries feature packages size/XXL viz:charts Namespace | Anything related to viz types

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant