feat: Use per-context replay status #403
Conversation
18745f5 to
216aae2
Compare
216aae2 to
3b35b3e
Compare
| this.isReplaying = false; | ||
| @Override | ||
| public boolean isReplayingContext() { | ||
| return false; |
There was a problem hiding this comment.
Yes, intentional. The default returns false (don't suppress) which is the safe default. Only DurableContextImpl overrides it with actual replay tracking. The only other subclass is StepContextImpl, whose user function only runs during real execution - so its logs should never be suppressed.
|
|
||
| /** Returns whether this context is currently in replay mode. */ | ||
| @Override | ||
| public boolean isReplaying() { |
There was a problem hiding this comment.
removing an existing method would be a breaking change. We'll need a major version upgrade if we really want to remove this.
There was a problem hiding this comment.
Can mark it as deprecated and remove in future.
|
I think this change is no longer required by our plugin interface and the OTel plugin as we are going to switch to a backend based approach. |
|
Closing this PR, this will be fixed by #435 |
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
Issue Link, if available
Fixes #383
Adds per-context replay tracking to the Java SDK. This is a prerequisite for the plugin hooks feature (#364) and OTel integration (#333).
Problem
Log suppression during replay used the global
ExecutionManager.isReplaying()flag. When multiple branches run concurrently (parallel/map), the global flag flips to EXECUTION as soon as any branch encounters new work - causing logs in other branches that are still replaying to leak through.The old per-context field (
BaseContextImpl.isReplaying) was a one-shot transition guard used only byBaseDurableOperation.execute(). It was never used for log suppression and answered a different question ("has this context ever seen a non-cached op?") rather than ("is the next operation already checkpointed?").Solution
Added proactive per-context replay tracking in
DurableContextImpl:replayModefield - initialized by checking if the next operation (viapeekNextOperationId()) exists in checkpoint storageupdateReplayStatus()- called afternextOperationId()in each operation method; peeks at the following operation and transitions out of replay if it doesn't existisReplayingContext()- exposes the per-context replay status to the logger and future plugin hooksThis matches the Python SDK's
_track_replay()pattern: after consuming the current operation's ID, peek at the next one - if it's not in storage, we're past the replay boundary.Checklist
Testing
Unit Tests
Have unit tests been written for these changes? Yes
Integration Tests
Have integration tests been written for these changes? N/A
Examples
Has a new example been added for the change? (if applicable) N/A