Repository navigation
Conversation
Contributor
Author
|
/gemini review |
Contributor
There was a problem hiding this comment.
📋 Review Summary
This PR resolves a race condition in portable Spark Streaming where subsequent micro-batches could execute before WatermarkAdvancingStreamingListener finished advancing watermarks for the prior batch, causing downstream stages in multi-GBK topologies to observe inconsistent watermarks. It also properly resets GlobalWatermarkHolder and MetricsAccumulator state in SparkPipelineRunner between sequential runs and synchronizes watermark state access in GlobalWatermarkHolder.
🔍 General Feedback
- Synchronizing
SingleEmitInputDStream.compute(Time)againstGlobalWatermarkHolder.getLastWatermarkedBatchTime()(matchingTestDStream's pattern) and guarding onGlobalWatermarkHolder.hasWatermarks()cleanly prevents out-of-order watermark reads across stages without hanging non-watermarked streams or checkpoint recovery tests. - Synchronizing
add,addAll,hasWatermarks, andgetinGlobalWatermarkHolderand resettingwatermarkCacheinclear()closes thread-safety and state-leakage gaps when multiple streaming pipelines run in the same JVM.
💡 Tip: Comment /gemini review on this pull request to trigger a new Gemini code review.
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.
Note: this PR was auto-generated by tooling. Before moving it out of draft, the author has done a full review of the PR, specifically evaluating it on the following criteria:
Full details of the methodology of generation and review can be found here - https://docs.google.com/document/d/14lj7ECVov4T4EdwmIzNlWrRGE3lLDMOwX5xUMGzaLoc/edit?usp=sharing
If you have concerns with the PR or with the underlying methodology used to generate this, please comment below - they will be addressed by the author not the tooling :)
Summary
Fixes a watermark synchronization race in Spark Runner DStream streaming pipelines (
PostCommit Java PVR Spark4 Streaming, e.g. https://github.com/apache/beam/actions/runs/43374186705/job/131716702201) whereCombineTest$BasicTests.testBinaryCombinePerKeyInstanceMethodReferencefailed with:Production Impact
Impacts real Spark Runner streaming pipelines (both Portable DStream streaming and Classic streaming pipelines using
Flatten/ImpulseviaSingleEmitInputDStream).GroupByKey/Combine.perKeytopologies where a micro-batch takes longer thanbatchIntervalMillis(default1000ms), or running multiple pipelines sequentially in the same JVM viaSparkPipelineRunner.TestDStream(waitForLastBatch) andWatermarkSyncedDStream(awaitWatermarkSyncWith),SingleEmitInputDStream.compute(Time)did not wait for the previous micro-batch's watermark advancement (GlobalWatermarkHolder.getLastWatermarkedBatchTime()) before generating the next micro-batch's RDD. When Batch 1 takes longer thanbatchIntervalMillis(e.g., while initializing the SDK harness), Spark Streaming'sJobGeneratorqueues Batch 2 while Batch 1 is still executing. As soon as Batch 1's Spark job finishes,JobScheduler.jobExecutorstarts executing Batch 2 concurrently withWatermarkAdvancingStreamingListener.onBatchCompleted(Batch 1)running on Spark's asynchronousLiveListenerBusthread.SparkGroupAlsoByWindowViaWindowSetfetchesGlobalWatermarkHolder.get(...)lazily inside each stage on the executor, an upstreamGroupByKeystage (Combine.perKey) in Batch 2 can readGlobalWatermarkHolder.get(...)beforeadvance()completes (seeingTIMESTAMP_MIN_VALUEand not firing its buffered elements), while a downstreamGroupByKeystage (PAssert) in the same Batch 2 readsGlobalWatermarkHolder.get(...)milliseconds later afteradvance()completes (seeingTIMESTAMP_MAX_VALUEand firing premature timers before upstream results arrive).SparkPipelineRunner.rundid not callGlobalWatermarkHolder.clear()orMetricsAccumulator.clear()(unlikeTestSparkRunner.run), leaving static watermark and metrics state dirty across sequential pipeline runs in the same JVM, andGlobalWatermarkHolder.add/getwere not synchronized withadvance.SingleEmitInputDStream.compute(Time)now waits forGlobalWatermarkHolder.getLastWatermarkedBatchTime() >= lastValidTimeMswhen watermarks are registered (matchingTestDStream), ensuring BatchN+1is not generated until BatchN's watermark update has completed.GlobalWatermarkHolder.add,addAll,get, andhasWatermarksonGlobalWatermarkHolder.class, and resetswatermarkCacheinclear().MetricsAccumulatorandGlobalWatermarkHolderinSparkPipelineRunner.runbefore starting a pipeline.Verification
beam_PostCommit_Java_PVR_Spark4_Streaming.ymlworkflow run on branch:43388934435