jbonofre opened a new pull request, #41013:
URL: https://github.com/apache/beam/pull/41013

   On runners that execute unbounded sources as splittable DoFns, such as 
Dataflow Runner v2, JmsIO acknowledges only a small fraction of the messages it 
reads. The rest are redelivered and processed again.
   
   ## Cause
   
   `UnboundedSourceAsSDFRestrictionTracker.getProgress()` calls 
`currentRestriction()`, which calls `getCheckpointMark()` on the live reader. 
The SDK harness calls `getProgress()` on every progress request during a bundle.
   
   For JmsIO, `getCheckpointMark()` is not a snapshot. It moves the messages 
read so far into a new checkpoint, gives that checkpoint the current session 
and consumer, and opens new ones. The progress code drops that checkpoint, so 
it is never finalized. Only the messages read after the last progress request 
get acknowledged.
   
   The dropped checkpoints also keep their session and consumer open until the 
reader's connection closes after `closeTimeout`. The broker then redelivers 
their messages.
   
   This matches what we saw on a Dataflow streaming job (CLIENT_ACKNOWLEDGE, 
`withRequiresDeduping()`):
   - about 1% of the messages acknowledged;
   - no errors logged;
   - a few hundred messages in flight per broker;
   - 17 to 23 consumers per broker for 2 readers.
   
   #40605 did not change this, because Dataflow finalizes the in-memory 
checkpoint, never a restored copy. We have not yet confirmed that this job runs 
on Runner v2; the DEBUG logs below will show it.
   
   ## Changes
   
   **Core (`Read.java`):** progress reporting no longer calls 
`getCheckpointMark()`. It checks for the empty reader or the maximum watermark 
directly. `UnboundedReader#getCheckpointMark()` documents that the elements 
read between two calls form one bundle, so it must not be called only to report 
progress.
   
   **JmsIO:**
   - **Earlier checkpoints:** finalizing a checkpoint also acknowledges the 
earlier checkpoints of the same reader that are not finalized yet. This is safe 
because a runner commits a checkpoint only once all earlier checkpoints of the 
same reader are committed (same javadoc). It fixes JmsIO on Beam versions 
without the core change, and when a finalize callback is lost.
   - **Resuming:** `createReader(options, checkpoint)` acknowledges the 
checkpoint it resumes from, and the earlier ones, when the reader that took it 
lives in this JVM. A runner resumes only from committed checkpoints; the direct 
runner already finalizes a checkpoint when it resumes from it. This replaces 
the per-checkpoint registry of #40605 with a per-reader one: a checkpoint now 
carries its reader id and a sequence number instead of a random id. As a 
result, an empty checkpoint can also acknowledge the earlier ones.
   - **closeTimeout:** when the connection closes after `closeTimeout` with 
checkpoints still pending, those checkpoints are dropped instead of being 
acknowledged later on a closed connection. An INFO line reports how many 
messages the broker will redeliver.
   - **Logging:** DEBUG logs for reader creation, connection and close, and for 
each checkpoint holding messages, including the first stack frames outside 
JmsIO, which show whether a checkpoint ends a bundle or was taken for progress. 
Finalization also logs how many messages and earlier checkpoints it 
acknowledged. To enable them, use 
`--sdkHarnessLogLevelOverrides={"org.apache.beam.sdk.io.jms":"DEBUG"}` on 
Runner v2, or `--workerLogLevelOverrides` on the legacy Dataflow worker.
   
   ## Compatibility
   
   Checkpoints written by released versions still decode, since 
`serialVersionUID` is unchanged. They carry no reader id, so there is nothing 
to acknowledge after restoring them, as before. The `id` field from #40605 was 
never in a release.
   
   ## Tests
   
   - `ReadTest`: progress no longer takes a checkpoint, while `trySplit` still 
does. This test fails without the core change.
   - `JmsLocalTest`:
     - finalizing acknowledges earlier checkpoints, but not later ones;
     - an empty checkpoint acknowledges the earlier ones;
     - resuming from a restored checkpoint acknowledges it;
     - `closeTimeout` drops pending checkpoints.
   - `JmsIOTest` (embedded broker, ActiveMQ and Qpid clients):
     - a checkpoint taken mid-bundle is acknowledged together with the next one;
     - resuming from a checkpoint acknowledges it.
   


-- 
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