Skip to content

fix(csharp): auto-close server operation when result stream is exhausted#351

Closed
msrathore-db wants to merge 1 commit intomainfrom
fix/auto-close-exhausted-reader
Closed

fix(csharp): auto-close server operation when result stream is exhausted#351
msrathore-db wants to merge 1 commit intomainfrom
fix/auto-close-exhausted-reader

Conversation

@msrathore-db
Copy link
Collaborator

Summary

Fixes abandoned PowerBI result fetches that prevent SQL warehouse auto-stop. Affects ~5,000 warehouses daily, wasting ~30,000 compute-hours/day fleet-wide.

Root cause: DatabricksCompositeReader only sends TCloseOperationReq inside Dispose(). Power BI's M engine (Power Query) has no using blocks or deterministic disposal — it relies on GC to clean up IArrowArrayStream objects. Since the reader has no finalizer, GC collects it silently without closing the server command. Commands stay open for ~22 min (CommandInactivityTimeout), and the autostop scheduler sees HasOnClusterOrSchedulingCommand=true, blocking warehouse shutdown.

Fix (single file: DatabricksCompositeReader.cs):

  • Auto-close on exhaustion: When ReadNextRecordBatchAsync returns null, send TCloseOperationReq immediately via CloseOperationBestEffort(). This covers the dominant PowerBI pattern (Table.Buffer() reads all results).
  • Finalizer safety net: Add ~DatabricksCompositeReader() for readers abandoned without any reads (e.g., cancelled previews).
  • Idempotent Dispose: _operationClosed flag prevents duplicate TCloseOperationReq when both auto-close and Dispose() fire.

Test plan

Verified with A/B repro against warehouse 00adc7b6c00429b8 (5-min auto-stop timeout):

Run Driver Result
Without fix Original Warehouse stayed RUNNING 10+ min past last query
With fix Auto-close on exhaustion Warehouse auto-stopped within timeout
Fix commented out Original (control) Warehouse stayed RUNNING again

Repro tool at csharp/tools/AbandonedResultRepro/ — executes queries, reads all results without calling Dispose(), holds process alive 10 min.

  • Verify existing unit tests pass
  • Verify E2E tests pass (CloudFetch + inline results)
  • Verify PowerBI connector works end-to-end with fixed driver

This pull request was AI-assisted by Isaac.

When ReadNextRecordBatchAsync returns null (all results consumed), send
TCloseOperationReq to the server immediately instead of waiting for
Dispose(). Power BI's M engine has no deterministic disposal — it relies
on GC to clean up IArrowArrayStream objects. Without a finalizer or
auto-close, server commands stay open for ~22 min (CommandInactivityTimeout),
blocking warehouse autostop even when no queries are running.

Changes:
- Send CloseOperation via CloseOperationBestEffort() when results are
  exhausted (covers Table.Buffer, schema inference, metadata calls)
- Add finalizer as safety net for abandoned readers never read
- Add _operationClosed flag to prevent duplicate TCloseOperationReq
- Make Dispose() idempotent with exhaustion-triggered close

Tested with A/B repro against warehouse with 5-min auto-stop:
- Without fix: warehouse stayed running 10+ min past last query
- With fix: warehouse auto-stopped within timeout

Co-authored-by: Isaac
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.

1 participant