Skip to content

feat(appkit-ui): share in-flight useAnalyticsQuery requests - #524

Draft
MarioCadenas wants to merge 1 commit into
mainfrom
in-flight-requests
Draft

feat(appkit-ui): share in-flight useAnalyticsQuery requests#524
MarioCadenas wants to merge 1 commit into
mainfrom
in-flight-requests

Conversation

@MarioCadenas

Copy link
Copy Markdown
Collaborator

What

useAnalyticsQuery deduplicates identical in-flight requests. When multiple components call the hook with the same query key, parameters, format, and dev mode, they now share a single network request instead of each firing its own.

Closes #496.

How

  • New analytics-request-store.ts — a module-singleton request store mirroring the existing ResourceStatusStore idiom (keyed Map + subscribe/notify + immutable snapshot via useSyncExternalStore). It owns the transport lifecycle (SSE for JSON_ARRAY, direct Arrow fetch for ARROW_STREAM) and fans both the final result and mid-flight warehouse_status updates out to every subscriber.
  • use-analytics-query.ts becomes a thin useSyncExternalStore subscriber. Cache key = urlSuffix + serialized({parameters, format}). Warehouse-status mirroring into ResourceStatusProvider moved from the transport into a hook effect.
  • Lifecycle: a keyed entry lives as long as it has subscribers. Teardown is deferred one tick after the last unsubscribe, so a React StrictMode unmount→remount (or fast route swap) reuses the in-flight request instead of aborting and refetching. Late subscribers read the current snapshot immediately (including an already-resolved result). Dedup-only — no cross-lifecycle result cache.

useChartData and all charts route through useAnalyticsQuery, so they inherit dedup for free. UseAnalyticsQueryResult is unchanged — non-breaking.

Showcase

New /query-dedup playground route (Data → "Query Dedup"). It wraps window.fetch while mounted to count analytics POSTs in-page, so you can watch "N components mounted → 1 network request fired" without the DevTools Network tab. Buttons mount more panels (count stays 1) and give the last panel a different key (count ticks to 2, proving distinct keys still fan out).

Testing

  • appkit-ui suite: 371 passed / 18 files, including new dedup + store-lifecycle tests and the warehouse-status integration tests (both test files reset the singleton store between cases).
  • appkit-ui typecheck: clean. dev-playground client tsc --noEmit: clean.
  • biome check and knip: clean.

Not yet run end-to-end against a live warehouse (no creds in this environment); the dedup counter is exercised by the request-store tests regardless of query success.

Identical analytics requests (same query key, parameters, format, and dev
mode) now share a single in-flight network request instead of one per hook
instance. A module-singleton request store (mirroring the ResourceStatusStore
idiom) owns the transport; useAnalyticsQuery becomes a useSyncExternalStore
subscriber. Late subscribers read the current snapshot; the request is torn
down a tick after the last subscriber unmounts, so a StrictMode
unmount->remount reuses it rather than aborting.

useChartData and all charts inherit the dedup for free. Dedup-only, no result
cache. UseAnalyticsQueryResult is unchanged (non-breaking).

Adds a /query-dedup playground route that counts analytics fetches in-page to
make the behavior observable.

Closes #496

Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 827 KB — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 855 KB 298 KB
Type declarations 314 KB 108 KB
Source maps 1.7 MB 557 KB
Other 11 KB 3.7 KB
Total 2.8 MB 967 KB
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 87 KB 2.5 KB 90 KB external 285 KB
./beta 48 KB 459 B 48 KB external 140 KB
./type-generator 20 KB 0 B 20 KB external 57 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 83 KB
. utils.js initial 4.0 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 32 KB
./beta stream-manager.js initial 5.8 KB
./beta wide-event-emitter.js initial 3.2 KB
./beta databricks.js initial 3.0 KB
./beta configuration.js initial 2.1 KB
./beta service-context.js initial 1.3 KB
./beta client.js initial 431 B
./beta client-options.js initial 220 B
./beta supervisor-api.js lazy 194 B
./beta databricks.js lazy 142 B
./beta index.js lazy 123 B
./type-generator index.js initial 20 KB

@databricks/appkit-ui

npm tarball (packed): 314 KB (+5.2 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 366 KB (+3.9 KB) 122 KB (+1.8 KB)
Type declarations 209 KB (+341 B) 76 KB (+152 B)
Source maps 700 KB (+7.4 KB) 230 KB (+3.2 KB)
CSS 16 KB 3.3 KB
Total 1.3 MB (+12 KB) 432 KB (+5.1 KB)
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
./js 4.3 KB 49 KB 54 KB 208 KB 12 KB
./js/beta 20 B 0 B 20 B 0 B 0 B
./react 429 KB (+229 B) 49 KB 478 KB (+229 B) 1.3 MB (+16 B) 169 KB (+743 B)
./react/beta 1.0 KB 0 B 1.0 KB 0 B 1.9 KB

Chunks:

Entry Chunk Load Size (gz)
./js index.js initial 4.2 KB
./js chunk initial 120 B
./js apache-arrow lazy 49 KB
./js/beta beta.js initial 20 B
./react index.js initial 427 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 1.0 KB

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 31167158174 -R databricks/appkit -n appkit-template-0.55.1-pr.7e39751-in-flight-requests-524 -D appkit-pr-524 \
  && unzip -o "appkit-pr-524/appkit-template-0.55.1-pr.7e39751-in-flight-requests-524.zip" -d "appkit-pr-524" \
  && databricks apps init --template "appkit-pr-524"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useAnalyticsQuery issues duplicate network requests for identical queries across hook instances

1 participant