gschlueter-jaconi opened a new issue, #39970:
URL: https://github.com/apache/beam/issues/39970

   ### What happened?
   
   ## Environment
   
   - Apache Beam Java SDK 2.75.0
   - Google Cloud Dataflow / Portable Runner
   - Exactly one active job and one worker
   - Stable, explicitly configured `changeStreamName`
   
   ## Configuration
   
   ```java
   BigtableIO.readChangeStream()
       .withProjectId(projectId)
       .withInstanceId(instanceId)
       .withTableId(tableId)
       .withAppProfileId(appProfileId)
       .withMetadataTableTableId(metadataTableId)
       .withChangeStreamName(changeStreamName)
       .withExistingPipelineOptions(
           BigtableIO.ExistingPipelineOptions.RESUME_OR_NEW);
   ```
   
   ## Observed behavior
   
   1. The job starts normally and consumes every event once.
   2. After approximately 30 minutes, the running job logs:
   
      ```text
      Resuming from previous pipeline with low watermark of ...
      ```
   
   3. Every subsequent event is then consumed exactly twice.
   4. No second job is started and the worker count remains one.
   5. The duplicate consumption is persistent, not just a short overlap during 
a checkpoint.
   6. Omitting `withExistingPipelineOptions(...)`, thereby using the default 
`FAIL_IF_EXISTS`, prevents the problem.
   
   ## Expected behavior
   
   Retries, checkpointing, or repeated initialization within the same active 
job must not cause it to resume itself or create another consumer for 
partitions already being consumed.
   
   ## Suspected cause
   
   Dataflow can re-execute `InitializeDoFn`. After the current job has created 
its metadata, `RESUME_OR_NEW` appears to interpret that metadata as belonging 
to a previous pipeline. The observed `Resuming from previous pipeline...` log 
line indicates that this branch is executed while the original consumer is 
still active.
   
   `ResumeFromPreviousPipelineAction` restores the existing partition UUIDs. 
The locking code in `MetadataTableDao.lockAndRecordPartition()` considers an 
existing lock with the same UUID successfully held:
   
   ```java
   if (doHoldLock(
           partitionRecord.getPartition(),
           partitionRecord.getUuid())) {
       return true;
   }
   ```
   
   The original and resumed readers can therefore both pass the lock check and 
open change-stream RPCs for the same partitions.
   
   The workaround supports this explanation. With the default `FAIL_IF_EXISTS`, 
repeated initialization detects the existing metadata and returns without 
emitting another `InitialPipelineState`, preventing another downstream consumer 
chain from starting.
   
   ## Workaround
   
   Omit `withExistingPipelineOptions(...)`. This prevents duplicate 
initialization, but it also prevents a legitimate later job from resuming 
existing metadata, so it is not a complete solution.
   
   ## Suggested fixes
   
   1. Make initialization idempotent per job execution. Store a unique 
execution identifier in the metadata and claim initialization atomically. 
Re-execution with the same identifier should emit nothing, while a genuinely 
new job should still be allowed to resume.
   
   2. Add a durable checkpoint or reshuffle boundary between `InitializeDoFn` 
and the unbounded `DetectNewPartitionsDoFn`. This should ensure that retries or 
backup executions of initialization cannot start multiple downstream consumer 
chains.
   
   ### Issue Priority
   
   Priority: 2 (default / most bugs should be filed as P2)
   
   ### Issue Components
   
   - [ ] Component: Python SDK
   - [ ] Component: Java SDK
   - [ ] Component: Go SDK
   - [ ] Component: Typescript SDK
   - [x] Component: IO connector
   - [ ] Component: Beam YAML
   - [ ] Component: Beam examples
   - [ ] Component: Beam playground
   - [ ] Component: Beam katas
   - [ ] Component: Website
   - [ ] Component: Infrastructure
   - [ ] Component: Spark Runner
   - [ ] Component: Flink Runner
   - [ ] Component: Prism Runner
   - [ ] Component: Twister2 Runner
   - [ ] Component: Hazelcast Jet Runner
   - [ ] Component: Google Cloud Dataflow Runner


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to