Skip to content

Fix #1354 - Isolate variables in ForExecutor to avoid racing condition to overwrite loop variables#1363

Merged
ricardozanini merged 5 commits intoserverlessworkflow:mainfrom
ricardozanini:fix-forexecutor-async
May 5, 2026
Merged

Fix #1354 - Isolate variables in ForExecutor to avoid racing condition to overwrite loop variables#1363
ricardozanini merged 5 commits intoserverlessworkflow:mainfrom
ricardozanini:fix-forexecutor-async

Conversation

@ricardozanini
Copy link
Copy Markdown
Member

@ricardozanini ricardozanini commented May 2, 2026

Many thanks for submitting your Pull Request ❤️!

What this PR does / why we need it:
Fixes #1354

Special notes for reviewers:

  • I changed the InMemoryEvents class slightly to be inherit-friendly
  • Moved TranceExecutionListener to impl so it can easily be reused in other tests and in client code - it's quite useful for debugging/tracing, even in prod code.

Additional information (if needed):

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses issue #1354 by changing how ForExecutor handles loop variables to prevent async tasks (e.g., emit) from observing overwritten $item/$index values. It also refactors supporting test utilities by making InMemoryEvents subclass-friendly, introducing a lagged event broker for deterministic async tests, and relocating TraceExecutionListener into impl code for reuse.

Changes:

  • Update ForExecutor to capture per-iteration loop values and reapply them at execution time in the async chain.
  • Make InMemoryEvents fields protected/final to support subclassing; add LaggedInMemoryEvents for regression testing async behavior.
  • Move TraceExecutionListener into io.serverlessworkflow.impl.lifecycle and update tests/tools to import it from the new package.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
impl/test/src/test/java/io/serverlessworkflow/impl/test/MvStorePersistenceTest.java Update import to new TraceExecutionListener package.
impl/test/src/test/java/io/serverlessworkflow/impl/test/DBGenerator.java Update import to new TraceExecutionListener package.
impl/core/src/main/java/io/serverlessworkflow/impl/lifecycle/TraceExecutionListener.java Change package to impl.lifecycle (and remove now-redundant imports).
impl/core/src/main/java/io/serverlessworkflow/impl/executors/ForExecutor.java Attempt to fix foreach race by capturing item/index and re-setting variables in the async callback.
impl/core/src/main/java/io/serverlessworkflow/impl/events/InMemoryEvents.java Expose internals as protected to allow inheritance in tests/client code.
experimental/test/src/test/java/io/serverlessworkflow/fluent/test/LaggedInMemoryEvents.java New lagged publisher used to make async foreach behavior reproducible.
experimental/test/src/test/java/io/serverlessworkflow/fluent/test/ForEachFuncTest.java Switch to lagged broker and add listener to help validate the foreach/emit regression.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread impl/core/src/main/java/io/serverlessworkflow/impl/executors/ForExecutor.java Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Collaborator

@fjtirado fjtirado left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put back traceExecutionListerns as test class.
This will avoid unrelated change in DBGbenrator and MvStorePersistenceTest.

Comment thread impl/core/src/main/java/io/serverlessworkflow/impl/events/InMemoryEvents.java Outdated
@fjtirado
Copy link
Copy Markdown
Collaborator

fjtirado commented May 5, 2026

@ricardozanini Nice pr that fixes that particular race condition, but I realized that ForExecutor was not properly implemented, there are more race conditions and opened this alternate one, please take a look
#1369, if you agree, I think we can close this one

fjtirado added a commit to fjtirado/sdk-java that referenced this pull request May 5, 2026
…d for multithread

Signed-off-by: fjtirado <ftirados@redhat.com>
ricardozanini and others added 4 commits May 5, 2026 11:25
Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
…id racing condition to overwrite loop variables

Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
…d for multithread

Signed-off-by: fjtirado <ftirados@redhat.com>
@ricardozanini ricardozanini force-pushed the fix-forexecutor-async branch from 2e95a6c to 19f8c9b Compare May 5, 2026 15:33
@ricardozanini ricardozanini added 🍒 cherry-pick This PR is a cherry-pick and removed do not merge labels May 5, 2026
@fjtirado fjtirado self-requested a review May 5, 2026 15:40
Signed-off-by: Ricardo Zanini <ricardozanini@gmail.com>
@fjtirado fjtirado requested a review from Copilot May 5, 2026 15:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ricardozanini ricardozanini merged commit bb7586b into serverlessworkflow:main May 5, 2026
3 checks passed
@ricardozanini ricardozanini deleted the fix-forexecutor-async branch May 5, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🍒 cherry-pick This PR is a cherry-pick

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ForExecutor race condition: shared TaskContext causes wrong items to be processed in async loops

3 participants