Skip to content

[Spark][#36841] Register Spark's streaming internals with Kryo for the Structured Streaming runner - #39939

Merged
Abacn merged 2 commits into
apache:masterfrom
tkaymak:spark4-streaming-slice2-kryo
Sep 1, 2026
Merged

[Spark][#36841] Register Spark's streaming internals with Kryo for the Structured Streaming runner#39939
Abacn merged 2 commits into
apache:masterfrom
tkaymak:spark4-streaming-slice2-kryo

Conversation

@tkaymak

@tkaymak tkaymak commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Second slice of the Spark 4 Structured Streaming work split out of #39576, following the dispatch seam in #39906. Addresses #36841.

A Structured Streaming query serializes two Spark internals behind the runner's back, so streaming pipelines fail under spark.kryo.registrationRequired=true without these registrations:

  • StateSchemaMetadata is broadcast for every transformWithState query.
  • MemoryWriterCommitMessage is the memory sink's commit message, nested inside the already registered DataWritingSparkTaskResult.

Design notes:

  • Registered by name: the classes only exist as of Spark 4, and the shared sources are compiled once per Spark version into separate artifacts, so a direct reference would break the Spark 3 build. ClassNotFound is caught and logged, Spark 3 behavior is unchanged.
  • JavaSerializer covers their whole Scala object graph without tracking Spark's internal field layout across versions. Neither is on a hot path.
  • The call sits at the end of the registrator so the auto assigned Kryo ids of every registration above stay identical in the Spark 3 and Spark 4 artifacts.

SparkKryoRegistratorStreamingTest locks down both registrations and the id parity.

Full :runners:spark:3:test and :runners:spark:4:test suites green locally on JDK 17 plus spotless, checkstyle and a live ErrorProne compile.

Next slices in order: the DataSourceV2 unbounded source, the state and timer bridge on transformWithState, and the translators with the end to end tests. End to end evidence remains in draft #39576.

R: @Abacn

A Structured Streaming query serializes two Spark internals behind the
runner's back, so streaming pipelines fail spark.kryo.registrationRequired
without these registrations:

- StateSchemaMetadata is broadcast for every transformWithState query,
  hit on the very first micro-batch of any pipeline using Beam state or
  timers.
- MemoryWriterCommitMessage is the memory sink's commit message, nested
  inside the already registered DataWritingSparkTaskResult.

Both are registered by name because the shared base also compiles against
Spark 3, where neither class exists, and with a JavaSerializer so their
whole Scala object graph is covered without tracking Spark's internal
field layout across versions. Neither is on a hot path.

The registration call sits at the end of the registrator on purpose: Kryo
auto assigns ids sequentially, so appending these conditional, by-name
registrations keeps the auto assigned ids of everything above identical
on Spark 3 and Spark 4 classpaths.

SparkKryoRegistratorStreamingTest locks down both registrations and the
id parity.
@github-actions

Copy link
Copy Markdown
Contributor

Assigning reviewers:

R: @kennknowles added as fallback since no labels match configuration

Note: If you would like to opt out of this review, comment assign to next reviewer.

Available commands:

  • stop reviewer notifications - opt out of the automated review tooling
  • remind me after tests pass - tag the comment author after tests pass
  • waiting on author - shift the attention set back to the author (any comment or push by the author will return the attention set to the reviewers)

The PR bot will only process comments in the main thread (not review comments).

@Abacn Abacn left a comment

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.

Thanks! Had a few comments

Also have you checked a follow up from the previous PR? #39906 (comment)

kryo.register(TupleTagList.class);

// Spark internals only present when running streaming pipelines on Spark 4. These are
// registered by name because the shared runner base also compiles against Spark 3, where

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.

because the shared runner base also compiles against Spark 3

this isn't accurate. The sources are compiled on either Spark 3 or 4, producing different Beam artifact.

In any case, please simplify the comment strings. It's unnecessarily verbose as AI tends to write down all its try path into comments

@tkaymak tkaymak Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that makes sense. I will clean this up and follow up from #39906 in a separate small PR (#39952). Thank you!

@tkaymak tkaymak changed the title [#36841] Register Spark's streaming internals with Kryo for the Structured Streaming runner [Spark][#36841] Register Spark's streaming internals with Kryo for the Structured Streaming runner Sep 1, 2026
Corrects the compile model description, the shared sources are compiled
once per Spark version into separate artifacts, and trims the javadoc to
the essentials per review.
@tkaymak

tkaymak commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

Run Java PreCommit

@tkaymak

tkaymak commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

The Java PreCommit failure here is not this PR. gcr.io purged the cloud-sdk:316.0.0-emulators image that KafkaToPubsubE2ETest pins, so every Java PreCommit run is currently red, master included. Filed #39955, fix in #39956. Once that lands I will rerun the check here.

@Abacn Abacn left a comment

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.

Thanks!

@Abacn
Abacn merged commit e671af6 into apache:master Sep 1, 2026
16 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants