Skip to content

[SPARK-59242][SQL] Guard the DAGScheduler cleanup in SQLExecution against a stopped SparkContext - #58518

Open
ivoson wants to merge 1 commit into
apache:masterfrom
ivoson:SPARK-59242
Open

[SPARK-59242][SQL] Guard the DAGScheduler cleanup in SQLExecution against a stopped SparkContext#58518
ivoson wants to merge 1 commit into
apache:masterfrom
ivoson:SPARK-59242

Conversation

@ivoson

@ivoson ivoson commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

Guards the sc.dagScheduler dereferences in SQLExecution.withNewExecutionId0's finally block so a query unwinding while the SparkContext is being torn down no longer throws a NullPointerException that destroys the query's real failure.

SparkContext.stop() nulls _dagScheduler before it stops the listener bus, so a query that ends during teardown can reach sc.dagScheduler.cleanupQueryJobs(executionId) with a null receiver. Because that call runs in a finally, the NPE replaces the query's real exception rather than being suppressed, and it skips the rest of the block: the SparkListenerSQLExecutionEnd event is never posted, and observationManager.tryComplete is never called (leaving any Observation.get waiter blocked).

The activeQueryToJobs dereference under Utils.isTesting sits earlier in the same finally and hits the same race, so it is guarded as well; without that a test cannot reach the cleanupQueryJobs call site.

Why are the changes needed?

A query failing (or completing) exactly as its SparkContext is being stopped surfaces as an unclassified internal NullPointerException from SQLExecution, hiding the real error and leaving observation waiters hung, instead of propagating the true failure.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

UTs added.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 4.8)

…inst a stopped SparkContext

### What changes were proposed in this pull request?

Guards the `sc.dagScheduler` dereferences in `SQLExecution.withNewExecutionId0`'s
`finally` block so a query unwinding while the `SparkContext` is being torn down no
longer throws a `NullPointerException` that destroys the query's real failure.

`SparkContext.stop()` nulls `_dagScheduler` before it stops the listener bus, so a
query that ends during teardown can reach `sc.dagScheduler.cleanupQueryJobs(executionId)`
with a null receiver. Because that call runs in a `finally`, the NPE *replaces* the
query's real exception rather than being suppressed, and it skips the rest of the block:
the `SparkListenerSQLExecutionEnd` event is never posted, and
`observationManager.tryComplete` is never called (leaving any `Observation.get` waiter
blocked).

The `activeQueryToJobs` dereference under `Utils.isTesting` sits earlier in the same
`finally` and hits the same race, so it is guarded as well; without that a test cannot
reach the `cleanupQueryJobs` call site.

### Why are the changes needed?

A query failing (or completing) exactly as its `SparkContext` is being stopped surfaces
as an unclassified internal `NullPointerException` from `SQLExecution`, hiding the real
error and leaving observation waiters hung, instead of propagating the true failure.

### Does this PR introduce any user-facing change?

No. It only prevents an NPE from masking the real query outcome during context teardown.

### How was this patch tested?

New unit tests in `SQLExecutionSuite` that null out the `DAGScheduler` (standing in for
a stopped `SparkContext`, which nulls `_dagScheduler` before stopping the listener bus)
and assert that `withNewExecutionId` surfaces the body's real failure rather than an NPE,
and completes normally on the success path.

### Was this patch authored or co-authored using generative AI tooling?

Yes, ported from an internal Databricks Runtime fix using Claude Code (Opus 4.8).

Co-authored-by: Isaac <no-reply@databricks.com>
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