Skip to content

CompletionStage callbacks can prefer dispatcher over common ForkJoinPool#4

Draft
leviramsey wants to merge 10 commits intomainfrom
futureconverters-with-context
Draft

CompletionStage callbacks can prefer dispatcher over common ForkJoinPool#4
leviramsey wants to merge 10 commits intomainfrom
futureconverters-with-context

Conversation

@leviramsey
Copy link
Owner

The Scala standard library's conversion from Scala future to Java CompletionStage defines the "non-Async" versions to effectively call the Async version with the Java common ForkJoinPool specified. This subtly conflicts with the common understanding of the difference between the non-Async version, and the Asyncversion, as evidenced by various AI answers:

Copilot

thenCompose: Uses the thread of the previous stage; no new thread pool unless explicitly provided.
thenComposeAsync: If you don’t pass an Executor, it uses the ForkJoinPool.commonPool(). If you do pass an Executor, it uses that.

Gemini

thenCompose (without "Async") aims to run the dependent task on the same thread that completed the previous CompletableFuture.
thenComposeAsync guarantees that the dependent task will run on a different thread (either the default ForkJoinPool.commonPool() Executor or a specific Executor you provide).

The parasitic behavior of the non-Async version is not desirable for the futures returned by Akka (consider that the future returned from asking a remote actor would be completed on the remoting dispatcher!), but there's not a great reason to use the common FJP in an Akka application: the default dispatcher provides an FJP which is well-suited to short CPU-bound tasks (including with better observability).

This adapts the Scala standard library's conversion to one where the executor to prefer is specified at the time of conversion. CompletionStage-returning calls where it's practical to shift onto the default dispatcher are then adapted to use this:

  • asks of EntityRefs in typed cluster sharding
  • coordination lease operations
  • events-by-slice firehose methods which return completion stages

@leviramsey leviramsey marked this pull request as draft March 5, 2026 18:55
import scala.annotation.nowarn
import scala.jdk.DurationConverters._
import scala.jdk.FutureConverters._
//import scala.jdk.FutureConverters._

Choose a reason for hiding this comment

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

nit: Just remove

import akka.pattern.PromiseActorRef
import akka.pattern.StatusReply
import akka.util.{ ByteString, Timeout }
import akka.util.ByteString

Choose a reason for hiding this comment

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

These can be combined - likely would be via sbt formatting

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.

2 participants