Class WorkflowEngineCheckpointingSupport
- All Implemented Interfaces:
Checkpointing
Checkpointing implementation dedicated for a WorkflowEngine, to separate check pointing behavior
from it.
This class has one job: coordinate checkpoint requests and complete
onCheckpointAdvanced(Segment, TrackingToken) only after the host confirms that workflow-owned asynchronous
work is safe. It does not track processor progress or decide when the engine should switch to live mode.
Everything here is kept per segment. The processor hands out one CheckpointTrigger per claimed
segment, a request through it advances only that segment's stored token, and it is inert once that claim ends.
The trigger map is concurrent, and its updates are deliberately small: they never invoke processor or workflow
callbacks while a claim is being recorded or dropped. The coordinator callback supplied to
onCheckpointAdvanced(Segment, TrackingToken) re-enters the support only after all the
WorkflowExecution latches (attached by the WorkflowEngineCheckpointingSupport.CheckpointLatchCoordinator) have been crossed.
- Since:
- 5.4.0
- Author:
- Simon Zambrovski, Steven van Beelen
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceCoordinates workflow work that must complete before checkpoint advancement. -
Constructor Summary
ConstructorsConstructorDescriptionWorkflowEngineCheckpointingSupport(WorkflowEngineCheckpointingSupport.CheckpointLatchCoordinator checkpointLatchCoordinator) Creates checkpointing support for aWorkflowEngineusing the givencheckpointLatchCoordinator. -
Method Summary
Modifier and TypeMethodDescriptiononCheckpointAdvanced(Segment segment, TrackingToken requested) Invoked on the processing thread when the processor takes a checkpoint forsegmentthat must coverrequested.voidonSegmentClaimed(Segment segment, @Nullable TrackingToken from, CheckpointTrigger trigger) Invoked whensegmentis claimed, handing the unit theCheckpointTriggerit uses to declare safe positions for that segment.onSegmentReleased(Segment segment, TrackingToken requested) Invoked whensegmentis being released.
-
Constructor Details
-
WorkflowEngineCheckpointingSupport
public WorkflowEngineCheckpointingSupport(WorkflowEngineCheckpointingSupport.CheckpointLatchCoordinator checkpointLatchCoordinator) Creates checkpointing support for aWorkflowEngineusing the givencheckpointLatchCoordinator.- Parameters:
checkpointLatchCoordinator- adds a latch to coordinatedWorkflowExecutionsto ensure all have reached a safe point to advance the checkpoint
-
-
Method Details
-
onSegmentClaimed
public void onSegmentClaimed(Segment segment, @Nullable TrackingToken from, CheckpointTrigger trigger) Description copied from interface:CheckpointingInvoked whensegmentis claimed, handing the unit theCheckpointTriggerit uses to declare safe positions for that segment. Retain it keyed by segment; it is invalid afterCheckpointing.onSegmentReleased(Segment, TrackingToken).The
fromtoken is the position this segment resumes at, the same positionCheckpointing.onSegmentReleased(Segment, TrackingToken)carries. It shows how far along the stream the segment is before the first event is delivered, so a unit restoring state at claim time can see whether it is picking up a segment at the end of the stream or one that still has history to replay.Defaults to a no-op: a unit that obtains its trigger another way (typically through a
CheckpointTriggerhandler-method parameter) does not need to retain it here.Invoked synchronously as part of claiming the segment. Throwing from this method fails the claim cycle: the segment is not claimed and the coordinator retries it (after a back-off). This is deliberate: a component that never received its trigger could never checkpoint, so signal a genuine inability to accept the claim by throwing, but do not throw for transient conditions that a retained trigger would handle later.
- Specified by:
onSegmentClaimedin interfaceCheckpointing- Parameters:
segment- the segment that was claimedfrom- the segment's storedTrackingToken, the position processing resumes from, ornullwhen processing starts at the beginning of the streamtrigger- the handle to request checkpoints forsegment
-
onCheckpointAdvanced
public CompletableFuture<TrackingToken> onCheckpointAdvanced(Segment segment, TrackingToken requested) Description copied from interface:CheckpointingInvoked on the processing thread when the processor takes a checkpoint forsegmentthat must coverrequested. Ensure work is durable at least up torequested, discard buffered state, then return the highest token now safe, which may exceedrequestedif more async work has drained. The processor stores the reported token only after every returned future completes. When several checkpointing units share a segment, it does not simply store the lowest report: it reconciles their positions to a single agreed token (the highest any unit reported), re-requesting any unit that has not yet reached it, and stores that, so no unit is ever left durably ahead of the stored token.Contract: the returned token must
coverrequested. The processor only ever advances the stored token: a value at or behind the last stored checkpoint is ignored (never rewinds progress).Exceptional completion. A unit that cannot reach
requestedmust complete its future exceptionally (returning a token that does not coverrequestedis treated the same way). The checkpoint then fails and nothing is stored. The processor handles this as a processing error: it aborts the segment's worker and releases the segment, so the coordinator re-claims it (after a back-off) and resumes from the last stored checkpoint; the events since are redelivered. The stored token therefore never advances on a failed checkpoint, and no progress is lost; an isolated failure costs a segment re-claim and some redelivery.The returned future is the lever for the two workloads described on this type. For an in-memory projection with asynchronous persistence, complete the future once the snapshot of the in-memory state has become durable, reporting the snapshotted position; the processing thread then resumes immediately. For a truly asynchronous handler, complete the future only once the in-flight work has caught up far enough to cover
requested; the processor awaits it before resuming the segment's worker, so the checkpoint acts as a barrier that holds event handling until the asynchronous work has reached this position.- Specified by:
onCheckpointAdvancedin interfaceCheckpointing- Parameters:
segment- the segment being checkpointedrequested- the segment-scoped position this checkpoint must cover (the highest anyone requested, or the batch-end token in auto mode)- Returns:
- the highest token this unit is durably safe at; must cover
requestedand must not sit behind the last persisted checkpoint
-
onSegmentReleased
Description copied from interface:CheckpointingInvoked whensegmentis being released. Flush everything handled so far, discard the segment's local state, and report the highest token made durable; the processor reconciles it with any co-located units (the same way asCheckpointing.onCheckpointAdvanced(Segment, TrackingToken)) and stores the result while still holding the claim, then releases the claim. After this theCheckpointTriggerfor the segment is invalid.The returned token must lie in the range
[lastStoredCheckpoint, upTo]: it must not rewind below the last persisted checkpoint (a regressive value is ignored), and it cannot exceedupTo(a unit can only be durable up to what it was handed). Returning a token belowupTois the normal lagging case: the uncovered tail (from the returned token up toupTo) is simply reprocessed on the next claim. Forcing the value all the way up toupTois not required and is often impossible for asynchronous work.The same two workloads described on this type apply here. An in-memory projection with asynchronous persistence takes a final snapshot and completes the future once it is durable, normally reporting
upTo. A truly asynchronous handler completes the future once its in-flight work has drained as far as it can before the claim is given up, reporting whatever position is durable by then, typically lower thanupTo, with the uncovered tail reprocessed on the next claim. UnlikeonCheckpointAdvanced, reachingupTois not required here: there is no later request to satisfy, so an asynchronous unit may report best-effort progress rather than forcing a full drain.Exceptional completion. Unlike
Checkpointing.onCheckpointAdvanced(Segment, TrackingToken), a future that completes exceptionally here does not abort or retry: the segment is being given up regardless. The release still proceeds: the checkpoint simply does not advance for what the unit could not confirm, the claim is freed, and the uncovered tail (everything past the last stored checkpoint) is reprocessed when the segment is next claimed. There is nothing the framework can do about a genuine durability failure at release beyond this reprocessing, so a unit that knows a lower already-durable position should report it (return it) rather than fail, to keep the redelivered window as small as possible.Defaults to
onCheckpointAdvanced(segment, upTo), i.e. a full flush up to the consumed position. Because that delegate mustcoverits argument or complete exceptionally, the default does not advance the checkpoint on release if the unit cannot reachupTo(the claim is still released, per the exceptional-completion behaviour above); override this method to instead report a lower already-durable position (the relaxed, best-effort semantics) for an asynchronous unit that may legitimately lag behindupToat release.- Specified by:
onSegmentReleasedin interfaceCheckpointing- Parameters:
segment- the segment being releasedrequested- the segment'slastConsumedToken: the position to drain toward- Returns:
- the highest token durably persisted; at least the last persisted checkpoint and at most
upTo, and typically lower thanupTowhen asynchronous work is still in flight
-