Skip to content

[1.8.x] Fix reused fork-join task submissions - #3625

Closed
He-Pin wants to merge 1 commit into
apache:1.8.xfrom
He-Pin:backport-3621-1.8
Closed

He-Pin wants to merge 1 commit into
apache:1.8.xfrom
He-Pin:backport-3621-1.8

Conversation

@He-Pin

@He-Pin He-Pin commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Motivation

Backport #3621 to 1.8.x. Repeatedly submitting the same mailbox as a ForkJoinTask can corrupt a fork-join work queue through task identity reuse. Exceptional completion can also prevent subsequent submissions of that mailbox from running.

Modification

  • Always wrap execute(Runnable) submissions in a fresh PekkoForkJoinTask in both Pekko's Java 8 and Java 9+ fork-join executors.
  • Retain Mailbox extends ForkJoinTask and its existing methods for 1.x binary compatibility.
  • Adapt the resubmission regression tests from fix: stop handing a reused ForkJoinTask to the fork-join dispatcher #3621 to cover both executor implementations, including recovery after an exception and a plain Runnable control. Wire TestJdk9 to the actor module's CompileJdk9 output.
  • Document the fix and its built-in executor scope.

Result

Every submission through Pekko's built-in fork-join executors has an independent task identity and completion state. The mailbox binary shape is unchanged and no MiMa filters are needed. Custom executors that submit mailboxes directly to a raw JDK ForkJoinPool remain outside this backport's scope.

Tests

  • Both regression suites demonstrate the failure on the original executor code: each reports one expected failure and one passing control. Both pass with the fix.
  • Cross-Scala regression tests: 12 passed across Scala 2.12.21, 2.13.18, and 3.3.7, covering Test and TestJdk9.
  • Runtime checks: 2 tests passed on JDK 8; both executor suites passed on JDK 25 (4 tests, compiled with JDK 17).
  • Dispatcher, Mailbox, ForkJoin, and ActorSystem focused tests on JDK 17: 190 passed, 2 existing pending tests.
  • +mimaReportBinaryIssues, +headerCheckAll, headerCreateAll, scoped sortImports, native scalafmt for changed files, and git diff --check passed.
  • docs/paradox passed with -J--add-opens=java.base/java.lang=ALL-UNNAMED after the initial JDK 17 reflective-access failure. Initial disk-space and cross-JDK launcher/compiler setup failures were resolved before the successful checks above.
  • checkCodeStyle fails on pre-existing formatting in remote/src/test/scala/org/apache/pekko/remote/serialization/NestedPayloadDepthSpec.scala; that file is identical to origin/1.8.x.
  • PR_TARGET_BRANCH=origin/1.8.x validatePullRequest completed but was not fully green. LevelDB JNI lacks support for the Apple Silicon host, a Netty test cannot bind 127.0.1.1, and the aggregate run reported two TcpConnectionSpec timeouts and one FlowFlatMapConcatParallelismSpec timeout.
  • Both TCP cases passed individually on the original 1.8.x code and on the fixed code. The FlatMap suite passed all 387 tests when rerun on JDK 17 with sbt's exported test classpath and the same time factor. These isolated reruns do not replace the failed aggregate result; no assertions or timeouts were changed.
  • Auditable Qoder stdout review: No must-fix findings.

References

Refs #3621, #3620.

Motivation:
Repeatedly queueing the same mailbox ForkJoinTask can corrupt a fork-join
work queue through task identity reuse. Exceptional completion can also
prevent later submissions of that mailbox from running.

Modification:
Adapt apache#3621 so both the Java 8 and Java 9+ Pekko fork-join executors wrap
every Runnable submission in a fresh PekkoForkJoinTask. Retain Mailbox's
ForkJoinTask superclass and methods for 1.x binary compatibility.
Share the resubmission regression tests across both executor implementations,
wire TestJdk9 to the actor module's CompileJdk9 output, and document the
built-in executor scope.

Result:
Each built-in fork-join submission has an independent task identity and
completion state. Mailbox's binary shape is unchanged and no MiMa filters
are needed.

Tests:
- Both regression suites fail on the original executor code and pass with
  the fix. Each pre-fix suite reports one expected failure and one pass.
- Cross-Scala focused regression suites: 12 passed across 2.12.21, 2.13.18,
  and 3.3.7, covering Test and TestJdk9.
- Runtime checks: 2 tests passed on JDK 8; both executor suites passed on
  JDK 25 (4 tests), using JDK 17 to compile the latter.
- Dispatcher, Mailbox, ForkJoin, and ActorSystem focused tests: 190 passed,
  2 existing pending tests, on JDK 17.
- +mimaReportBinaryIssues and +headerCheckAll passed for all Scala versions.
- headerCreateAll, scoped sortImports, native scalafmt for the changed
  files, and git diff --check passed.
- docs/paradox passed with -J--add-opens=java.base/java.lang=ALL-UNNAMED.
  The first JDK 17 attempt failed on the existing Parboiled reflective
  access requirement; the retry with the JVM option passed.
- checkCodeStyle fails on the pre-existing formatting of
  remote/src/test/scala/org/apache/pekko/remote/serialization/NestedPayloadDepthSpec.scala.
  That file matches origin/1.8.x byte for byte and is outside this change.
- An initial MiMa attempt failed with no disk space; the final full run
  passed after space recovered and build concurrency was limited to 2.
- Initial cross-JDK launcher attempts hit Java 8 argument-file and JDK 25
  javac -Werror setup issues; final native-JDK-8 and runtime-only-JDK-25
  checks passed without changing repository build settings.
- PR_TARGET_BRANCH=origin/1.8.x validatePullRequest completed but failed:
  native LevelDB JNI does not include the host's Apple Silicon architecture,
  and the host cannot bind the 127.0.1.1 address used by a Netty test.
  It also reported two TcpConnectionSpec timeouts and one
  FlowFlatMapConcatParallelismSpec future timeout under the full run.
- Both TCP cases passed individually on the original 1.8.x code and on
  the fixed executors in an isolated worktree. The failed reads use
  CallingThreadDispatcher, not the modified fork-join submission path.
- FlowFlatMapConcatParallelismSpec passed all 387 tests when rerun with
  ScalaTest Runner on JDK 17 using sbt's exported test classpath and the
  same test time factor. No assertions or timeouts were changed.
- Qoder stdout review: No must-fix findings.

References:
Refs apache#3621, apache#3620, akka/akka-core#33019.
@He-Pin

He-Pin commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

I think it's better just do it as 2.0.0

@He-Pin He-Pin closed this Oct 13, 2026
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.

1 participant