Skip to content

[SPARK-56019][SQL] Close JDBC connection on task kill to unblock native socket reads#55268

Closed
sadikovi wants to merge 2 commits intoapache:masterfrom
sadikovi:SPARK-56019
Closed

[SPARK-56019][SQL] Close JDBC connection on task kill to unblock native socket reads#55268
sadikovi wants to merge 2 commits intoapache:masterfrom
sadikovi:SPARK-56019

Conversation

@sadikovi
Copy link
Copy Markdown

@sadikovi sadikovi commented Apr 9, 2026

What changes were proposed in this pull request?

Native JDBC socket reads (e.g. socketRead0 in ResultSet.next() and PreparedStatement.executeBatch()) do not respond to Thread.interrupt(). When the task reaper kills a task blocked in either call, the thread never unblocks and lingers indefinitely. This registers a TaskInterruptListener on both the read path (JDBCRDD.compute, just before executeQuery()) and the write path (JdbcUtils.savePartition, just after the connection is opened). On kill, the listener closes the Connection, which tears down the underlying TCP socket and causes the blocked native call to throw a SQLException. The existing finally blocks in both paths are updated to tolerate a connection that was already closed by the listener.

Why are the changes needed?

Tasks blocked in native JDBC reads silently ignore Thread.interrupt(), so the task reaper cannot terminate them. The threads pile up, exhaust the executor's thread pool, and eventually hang the executor. Closing the connection from the interrupt-listener side is the correct fix: JDBC 4.0 §9.6 requires all methods on a closed Connection to throw SQLException, and major drivers (PostgreSQL, MySQL, H2) implement this reliably. Closes SPARK-56019.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

Added JdbcTaskInterruptSuite covering both paths. Tests use mock JDBC objects and CountDownLatch to simulate threads blocked after executeQuery() (in ResultSet.next()) and in executeBatch(). Each test fires the interrupt listener while the mock is blocking, asserts conn.close() is called, and confirms the task thread unblocks and propagates the SQLException. A separate test verifies that a rollback() failure on an already-closed connection does not mask the original exception.

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

No.

@sadikovi sadikovi changed the title update [SPARK-56019] Close JDBC connection on task interrupt to unblock native socket reads Apr 9, 2026
@sadikovi sadikovi changed the title [SPARK-56019] Close JDBC connection on task interrupt to unblock native socket reads [SPARK-56019][SQL] Close JDBC connection on task kill to unblock native socket reads Apr 9, 2026
}
conn.close()
if (!conn.isClosed) {
conn.close()
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.

closing a already closed connection is not noop?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, you are right, it is based on the API doc. I just was not sure if I should wrap.
I removed, it also minimised the diff.

@cloud-fan
Copy link
Copy Markdown
Contributor

the killed CI jobs are unrelated, thanks, merging to master!

@cloud-fan cloud-fan closed this in 7d8df99 Apr 9, 2026
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.

3 participants