fix(appkit): don't block queries when the warehouse status probe fails - #588
Conversation
The warehouse readiness check calls `warehouses.get` to observe state before running a query. When that probe threw (e.g. the caller can submit statements to the warehouse but lacks CAN_VIEW to read its status, or a transient control-plane error) the error propagated and blocked the query. Readiness is a UX/auto-start optimization, not a correctness gate — the Statement Execution API auto-starts and waits for the warehouse on its own. Now a non-abort probe failure is recorded on the span and at debug level, then the poll returns so execution proceeds. Real cancellations still surface as canceled, and a successful get returning DELETED/DELETING or STOPPED (autoStart=false), plus start/timeout failures, still block. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
📦 Bundle size reportCompared against
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 1.2 MB (+29 KB) | 424 KB (+12 KB) |
| Type declarations | 443 KB (+15 KB) | 161 KB (+6.9 KB) |
| Source maps | 2.3 MB (+61 KB) | 796 KB (+23 KB) |
| Other | 11 KB | 3.7 KB |
| Total | 4.0 MB (+105 KB) | 1.4 MB (+42 KB) |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
96 KB (+205 B) | 2.5 KB | 98 KB (+205 B) | external | 314 KB (+755 B) |
./beta |
93 KB (+112 B) | 457 B | 93 KB (+112 B) | external | 280 KB (+457 B) |
./testing |
38 KB (+22 KB) | 30 KB (+30 KB) | 69 KB (+52 KB) | external | 200 KB (+149 KB) |
./tsdown |
520 B | 0 B | 520 B | external | 813 B |
./type-generator |
23 KB | 0 B | 23 KB | external | 65 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 92 KB |
. |
utils.js |
initial | 4.0 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 76 KB |
./beta |
stream-manager.js |
initial | 5.8 KB |
./beta |
wide-event-emitter.js |
initial | 3.2 KB |
./beta |
databricks.js |
initial | 3.2 KB |
./beta |
configuration.js |
initial | 2.3 KB |
./beta |
service-context.js |
initial | 1.3 KB |
./beta |
client.js |
initial | 434 B |
./beta |
client-options.js |
initial | 220 B |
./beta |
supervisor-api.js |
lazy | 192 B |
./beta |
databricks.js |
lazy | 142 B |
./beta |
index.js |
lazy | 123 B |
./testing |
manifest.js |
initial | 26 KB |
./testing |
index.js |
initial | 10.0 KB |
./testing |
wide-event-emitter.js |
initial | 2.9 KB |
./testing |
index.js |
lazy | 26 KB |
./testing |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./testing |
utils.js |
lazy | 1.2 KB |
./tsdown |
index.js |
initial | 520 B |
./type-generator |
index.js |
initial | 23 KB |
@databricks/appkit-ui
npm tarball (packed): 350 KB (-4 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 395 KB | 132 KB |
| Type declarations | 229 KB | 84 KB (-1 B) |
| Source maps | 766 KB | 253 KB |
| CSS | 16 KB | 3.2 KB |
| Total | 1.4 MB | 473 KB (-1 B) |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
5.3 KB | 49 KB | 55 KB | 208 KB | 14 KB |
./js/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
./react |
432 KB | 49 KB | 481 KB | 1.3 MB | 177 KB |
./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 | 5.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 20 B |
./react |
index.js |
initial | 430 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 1.0 KB |
There was a problem hiding this comment.
🟡 Changes recommended
The readiness tests need stronger coverage of repeated failed probes and the SDK AbortError path.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This pull request makes warehouse status probing non-blocking for non-cancellation failures while preserving cancellation and readiness error handling.
Changes:
- Continues after non-abort
warehouses.getfailures with telemetry and debug logging. - Preserves cancellation, startup, timeout, and terminal-state behavior.
- Adds regression coverage for probe failures and cancellation.
File summaries
| File | Summary | Review findings |
|---|---|---|
packages/appkit/src/connectors/tests/sql-warehouse.test.ts |
Tests probe failures, cancellation, and sanitized start errors. | Moderate: add a second readiness call to verify failed probes are not cached (3 votes). Moderate: exercise the SDK AbortError branch without aborting the caller signal (1 vote). |
packages/appkit/src/connectors/sql-warehouse/client.ts |
Handles non-abort probe failures without blocking execution. | No findings. |
Review details
Suppressed comments (1)
packages/appkit/src/connectors/tests/sql-warehouse.test.ts:386
- Because this mock aborts the caller signal before rejecting,
_joinWarehouseReadinesscan reject locally through its abort handler without exercising the newAbortErrorbranch in_pollUntilWarehouseRunning. The test would still pass if that branch were removed; reject anAbortErrorwhile leaving the signal un-aborted (and keep caller-abort behavior covered separately) to test the changed path.
const get = vi.fn().mockImplementation(() => {
controller.abort();
const err = new Error("The operation was aborted");
err.name = "AbortError";
return Promise.reject(err);
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 35120248684 -R databricks/appkit -n appkit-template-0.75.1-pr.464744f-warehouse-readiness-588 -D appkit-pr-588 \
&& unzip -o "appkit-pr-588/appkit-template-0.75.1-pr.464744f-warehouse-readiness-588.zip" -d "appkit-pr-588" \
&& databricks apps init --template "appkit-pr-588"The template pins |
Signed-off-by: Atila Fassina <atila@fassina.eu>
#588) * fix(appkit): don't block queries when the warehouse status probe fails The warehouse readiness check calls `warehouses.get` to observe state before running a query. When that probe threw (e.g. the caller can submit statements to the warehouse but lacks CAN_VIEW to read its status, or a transient control-plane error) the error propagated and blocked the query. Readiness is a UX/auto-start optimization, not a correctness gate — the Statement Execution API auto-starts and waits for the warehouse on its own. Now a non-abort probe failure is recorded on the span and at debug level, then the poll returns so execution proceeds. Real cancellations still surface as canceled, and a successful get returning DELETED/DELETING or STOPPED (autoStart=false), plus start/timeout failures, still block. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu> * test(appkit): cover warehouse probe failure routing Signed-off-by: Atila Fassina <atila@fassina.eu> --------- Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
What
The warehouse readiness check (
SQLWarehouseConnector.ensureWarehouseRunning→_pollUntilWarehouseRunning) callswarehouses.getto observe warehouse statebefore running an analytics query. When that probe threw, the error
propagated up and blocked the query entirely.
This makes a failed status probe non-blocking: readiness is a UX/auto-start
optimization, not a correctness gate. The Statement Execution API auto-starts
and waits for the warehouse on its own, so an unobservable status shouldn't stop
the query.
Behavior
warehouses.getis now wrapped in a try/catch inside the poll loop:signal.aborted, or an SDKAbortError) still surfaceas
ExecutionError.canceled()— those are not probe failures.getfailure (e.g. caller can submit statements but lacksCAN_VIEWto read status, or a transient control-plane error) records thefailure on the
sql.warehouseReadyspan (warehouse.status_probe_failedevent + attribute) and at debug level, then returns so execution proceeds. The
RUNNING observation is not cached, so the next request probes again.
Deliberately unchanged (still block):
DELETED/DELETING→ConfigurationError.STOPPED+autoStart: false→ throws.warehouses.startfailures and readiness timeouts → still sanitized via_throwSanitizedReadinessError.Tests
startor emitting astatus.
startfailure (the path that still sanitizes), since a
getfailure no longerreaches it.
All 22 sql-warehouse tests and 44 analytics tests pass;
typecheckandlint/format are clean.
This pull request and its description were written by Isaac.