[SQL][SPARK-57318] Refactor WorkerSession into a state-machine interface - #56397
Closed
haiyangsun-db wants to merge 6 commits into
Closed
[SQL][SPARK-57318] Refactor WorkerSession into a state-machine interface#56397haiyangsun-db wants to merge 6 commits into
haiyangsun-db wants to merge 6 commits into
Conversation
hvanhovell
reviewed
Jun 9, 2026
…mination outcomes
Redesign the experimental UDF worker session interface so a concrete
transport backend can plug in cleanly:
- WorkerSession becomes a single AtomicReference-driven state machine
(Created -> Initializing -> Initialized -> Streaming -> Finishing,
with Cancelling/Finished/Cancelled/Failed/TransportFailed terminals).
init now returns InitResponse, process takes a finish thunk, and close
returns a Termination instead of throwing; cancel() is folded into close.
- New Termination sealed trait models the four terminal outcomes
(Finished/Cancelled/Failed/TransportFailed).
- New WorkerHandle trait decouples a session from the concrete provisioning
model; DirectWorkerProcess implements it and gains a cleanup-hook registry
so dispatchers register transport-specific cleanup (e.g. socket deletion).
- DirectWorkerDispatcher is generalized into abstract transport hooks
(newEndpointAddress / waitForReady / cleanupEndpointAddress / closeTransport
/ validateTransportSupport / newConnection / newSession / initialize), and
the concrete Unix-socket dispatcher/session are removed -- the first
concrete backend lands in the follow-up udf-worker-grpc change.
- WorkerConnection becomes a trait.
ExternalUDFExec is updated to the new close()/Termination finalizer (a single
task-completion listener now handles both success and failure).
Test scaffolding (TestDirectWorkerHelpers, DirectWorkerDispatcherSuite) is
adapted to the new API as an in-core UDS test dispatcher so core and sql/core
stay green; it moves to udf-worker-grpc alongside the concrete gRPC dispatcher
in the follow-up.
haiyangsun-db
force-pushed
the
pr2-udf-core-session-refactor
branch
from
June 9, 2026 22:48
f7931df to
e4bb07f
Compare
asf-gitbox-commits
pushed a commit
that referenced
this pull request
Jun 10, 2026
### What changes were proposed in this pull request? This PR refactors the experimental UDF worker **session interface** in the `udf-worker-core` module into an explicit state machine with well-defined terminal outcomes, so that a concrete transport backend can plug in cleanly. (The first such backend -- a gRPC-over-UDS dispatcher -- lands in a follow-up PR.) Core interface changes: - **`WorkerSession`** becomes a single `AtomicReference`-driven state machine (`Created -> Initializing -> Initialized -> Streaming -> Finishing`, with `Cancelling`/`Finished`/`Cancelled`/`Failed`/`TransportFailed` terminals). `init` now returns an `InitResponse`, `process` takes a `finish` thunk, and `close` returns a `Termination` instead of throwing; the previous separate `cancel()` is folded into `close()`. Subclasses implement `doInit` / `doProcess` / `doClose` hooks and drive transitions via protected helpers. - **`Termination`** (new) is a sealed trait modeling the four terminal outcomes: `Finished(FinishResponse)`, `Cancelled(CancelResponse)`, `Failed(ExecutionError)`, and `TransportFailed(Throwable)`. - **`WorkerHandle`** (new) is a small trait that decouples a session from the concrete worker-provisioning model. `DirectWorkerProcess` implements it and gains a cleanup-hook registry, so a dispatcher can register transport-specific cleanup (e.g. deleting a socket file) without the core hard-coding it. - **`DirectWorkerDispatcher`** is generalized from a Unix-socket-specific class into abstract transport hooks (`newEndpointAddress` / `waitForReady` / `cleanupEndpointAddress` / `closeTransport` / `validateTransportSupport` / `newConnection` / `newSession` / `initialize`). The concrete Unix-socket dispatcher and session (`DirectUnixSocketWorkerDispatcher`, `DirectWorkerSession`) are removed -- the first concrete backend is provided by the follow-up gRPC change. - **`WorkerConnection`** becomes a trait. Caller/test changes: - `ExternalUDFExec` (sql/core) is updated to the new `close()` / `Termination` finalizer: a single task-completion listener now handles both the success path (a `FinishResponse` has already arrived) and the failure/early-stop path (send `Cancel`, await `CancelResponse`), replacing the previous separate cancel-on-failure listener. - The in-core test scaffolding (`TestDirectWorkerHelpers`, `DirectWorkerDispatcherSuite`) is adapted to the new API as a small UDS-backed test dispatcher, so `udf-worker-core` and `sql/core` stay green. This scaffolding moves to the `udf-worker-grpc` module alongside the concrete gRPC dispatcher in the follow-up PR. Class hierarchy after this change: ``` WorkerSession (abstract state machine; close(): Termination) WorkerHandle (trait) <- DirectWorkerProcess DirectWorkerDispatcher (abstract transport hooks) WorkerConnection (trait) Termination = Finished | Cancelled | Failed | TransportFailed ``` ### Why are the changes needed? The previous `WorkerSession` tracked its lifecycle with a pair of `AtomicBoolean`s and signaled completion/cancellation by throwing, which does not cleanly express the several terminal outcomes a worker session can reach (clean finish, cancellation, user/worker error, transport failure) nor make worker reuse decisions explicit. It was also tied to a single Unix-socket transport. Reshaping it into an explicit state machine with a `Termination` result and abstract transport hooks gives a precise, testable lifecycle contract and lets a concrete transport (gRPC over UDS, in the follow-up) implement a small set of hooks rather than re-deriving lifecycle and termination handling. `WorkerHandle` and the cleanup-hook registry remove the core's dependence on a specific provisioning model. ### Does this PR introduce _any_ user-facing change? No. The UDF worker framework is experimental and currently unused by any released code path; this PR only reshapes its internal interfaces. ### How was this patch tested? Existing and adapted unit tests, run on top of `master`: - `build/sbt udf-worker-core/Test/compile` and `build/sbt sql/Test/compile` succeed. - `build/sbt "udf-worker-core/testOnly *DirectWorkerDispatcherSuite"` -- the dispatcher process-lifecycle suite (spawn / wait-for-ready / cleanup / error / timeout / concurrency) passes (31 tests) against the adapted in-core UDS test dispatcher. - `PythonUDFWorkerSpecificationSuite` (sql/core) is updated to the new `close()` signature and continues to spawn a real Python worker and verify reachability. ### Was this patch authored or co-authored using generative AI tooling? Yes Closes #56397 from haiyangsun-db/pr2-udf-core-session-refactor. Authored-by: Haiyang Sun <haiyang.sun@databricks.com> Signed-off-by: Herman van Hövell <herman@databricks.com> (cherry picked from commit bd04636) Signed-off-by: Herman van Hövell <herman@databricks.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
This PR refactors the experimental UDF worker session interface in the
udf-worker-coremodule into an explicit state machine with well-defined terminal outcomes, so that a concrete transport backend can plug in cleanly. (The first such backend -- a gRPC-over-UDS dispatcher -- lands in a follow-up PR.)Core interface changes:
WorkerSessionbecomes a singleAtomicReference-driven state machine (Created -> Initializing -> Initialized -> Streaming -> Finishing, withCancelling/Finished/Cancelled/Failed/TransportFailedterminals).initnow returns anInitResponse,processtakes afinishthunk, andclosereturns aTerminationinstead of throwing; the previous separatecancel()is folded intoclose(). Subclasses implementdoInit/doProcess/doClosehooks and drive transitions via protected helpers.Termination(new) is a sealed trait modeling the four terminal outcomes:Finished(FinishResponse),Cancelled(CancelResponse),Failed(ExecutionError), andTransportFailed(Throwable).WorkerHandle(new) is a small trait that decouples a session from the concrete worker-provisioning model.DirectWorkerProcessimplements it and gains a cleanup-hook registry, so a dispatcher can register transport-specific cleanup (e.g. deleting a socket file) without the core hard-coding it.DirectWorkerDispatcheris generalized from a Unix-socket-specific class into abstract transport hooks (newEndpointAddress/waitForReady/cleanupEndpointAddress/closeTransport/validateTransportSupport/newConnection/newSession/initialize). The concrete Unix-socket dispatcher and session (DirectUnixSocketWorkerDispatcher,DirectWorkerSession) are removed -- the first concrete backend is provided by the follow-up gRPC change.WorkerConnectionbecomes a trait.Caller/test changes:
ExternalUDFExec(sql/core) is updated to the newclose()/Terminationfinalizer: a single task-completion listener now handles both the success path (aFinishResponsehas already arrived) and the failure/early-stop path (sendCancel, awaitCancelResponse), replacing the previous separate cancel-on-failure listener.TestDirectWorkerHelpers,DirectWorkerDispatcherSuite) is adapted to the new API as a small UDS-backed test dispatcher, soudf-worker-coreandsql/corestay green. This scaffolding moves to theudf-worker-grpcmodule alongside the concrete gRPC dispatcher in the follow-up PR.Class hierarchy after this change:
Why are the changes needed?
The previous
WorkerSessiontracked its lifecycle with a pair ofAtomicBooleans and signaled completion/cancellation by throwing, which does not cleanly express the several terminal outcomes a worker session can reach (clean finish, cancellation, user/worker error, transport failure) nor make worker reuse decisions explicit. It was also tied to a single Unix-socket transport. Reshaping it into an explicit state machine with aTerminationresult and abstract transport hooks gives a precise, testable lifecycle contract and lets a concrete transport (gRPC over UDS, in the follow-up) implement a small set of hooks rather than re-deriving lifecycle and termination handling.WorkerHandleand the cleanup-hook registry remove the core's dependence on a specific provisioning model.Does this PR introduce any user-facing change?
No. The UDF worker framework is experimental and currently unused by any released code path; this PR only reshapes its internal interfaces.
How was this patch tested?
Existing and adapted unit tests, run on top of
master:build/sbt udf-worker-core/Test/compileandbuild/sbt sql/Test/compilesucceed.build/sbt "udf-worker-core/testOnly *DirectWorkerDispatcherSuite"-- the dispatcher process-lifecycle suite (spawn / wait-for-ready / cleanup / error / timeout / concurrency) passes (31 tests) against the adapted in-core UDS test dispatcher.PythonUDFWorkerSpecificationSuite(sql/core) is updated to the newclose()signature and continues to spawn a real Python worker and verify reachability.Was this patch authored or co-authored using generative AI tooling?
Yes