Skip to content

Fix reentrant BatchingExecutor execution#3331

Open
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/batching-executor-reentrancy
Open

Fix reentrant BatchingExecutor execution#3331
He-Pin wants to merge 1 commit into
apache:mainfrom
He-Pin:fix/batching-executor-reentrancy

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 11, 2026

Copy link
Copy Markdown
Member

Motivation

Fork-join workers can execute another submitted dispatcher batch on the same worker while helping a ForkJoinTask join. BatchingExecutor rejected that nested Batch.run or BlockableBatch.run invocation, producing requirement failed before the nested tasks could run.

Modification

  • Preserve and restore the previous batching context around both regular and blockable batch execution.
  • Add a deterministic regression test for both resubmitOnBlock modes and verify that the outer batch continues draining its queued work.
  • Document nested fork-join dispatcher execution and retain the dedicated-dispatcher guidance for external blocking.

Result

Reentrant batches execute without failing or losing the outer batch's queued work. The normal path reuses the existing ThreadLocal.get, adds no allocation or locking, and only adds a predictable null branch before the existing ThreadLocal.remove.

Tests

  • sbt "+actor-tests / Test / testOnly org.apache.pekko.dispatch.ExecutionContextSpec" - passed: 13 tests on Scala 2.13.18 and 13 tests on Scala 3.3.8.
  • sbt headerCreateAll +headerCheckAll checkCodeStyle "docs / paradox" - passed.
  • sbt +mimaReportBinaryIssues - passed on Scala 2.13.18 and Scala 3.3.8.
  • scalafmt --list --mode diff-ref=origin/main - passed.
  • git diff --check - passed.
  • sbt validatePullRequest - not completed; interrupted at requester direction (exit 130) during the long-running impacted-module suite. An earlier forked test JVM exited with code 255, so this run is not reported as passing.
  • Qoder CLI blocker review - No must-fix findings.

References

Fixes #1708

Motivation:
Fork-join workers can execute another submitted batch while helping a join. The nested batch hit a single-level ThreadLocal requirement and could drop queued work.

Modification:
Preserve and restore the previous batch context around Batch and BlockableBatch execution. Add deterministic coverage for both modes and document nested fork-join execution.

Result:
Reentrant batches run without failing, and outer queued tasks continue. Normal execution retains one ThreadLocal lookup with no added allocations or locking.

Tests:
- sbt +actor-tests / Test / testOnly org.apache.pekko.dispatch.ExecutionContextSpec - passed on Scala 2.13 and Scala 3
- sbt headerCreateAll +headerCheckAll checkCodeStyle docs / paradox - passed
- sbt +mimaReportBinaryIssues - passed
- scalafmt --list --mode diff-ref=origin/main - passed
- git diff --check - passed
- sbt validatePullRequest - stopped at user request before completion
- Qoder review - No must-fix findings

References:
Fixes apache#1708
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BatchingExecutor BlockableBatch.run: "requirement failed" under concurrent task invocations

1 participant