CompletionStage callbacks can prefer dispatcher over common ForkJoinPool - #32910
CompletionStage callbacks can prefer dispatcher over common ForkJoinPool#32910leviramsey wants to merge 6 commits into
Conversation
|
While I generally like this idea of improvement of the Java side, I have some doubt whether we should introduce it in a patch release. I think there is a quite hight risk that Java users doing blocking logic in |
Does this mean that whenever we run on the Akka FJP and then do asJava conversion from std lib it will switch over to Java's common FJP? This PR would change that for 3 specific cases, where the EntityRef.ask is most important. Wouldn't there be a gazillion more places where we convert with asJava? Would we replace more, including in downstream Akka libraries? |
|
Yeah, I think if we do it, it should be in a bigger release than patch, and we should do it across all libraries. |
|
Another, perhaps better, option than to implement in Akka would be to look into doing something with controllable/implicit ec in |
There's definitely that risk, though it's mitigated by the common advice on when to be parasitic, which is common enough lore for the AIs to be aware of it, e.g. Claude summarizes its answer for "In Java, when should I use thenApply versus thenApplyAsync" to:
And many of the blocking cases will actually be things like
There are plenty of such places, though the others in core are ones where we don't have easy access to the system dispatcher (e.g. classic ask pattern) without changing the API for callers, so it would be a choice between common FJP and the Scala global EC. (Kind of related: akka-http's Java
My understanding is that there's a very high bar for API-level changes in scala-lib (though @lrytz might correct me if wrong). |
|
I think we landed on, in conversation elsewhere, to make this opt in for now, and the default once we release the next minor. |
| /** Like the Scala stdlib FutureConverters, except shifts onto a provided execution context (rather than | ||
| * the ForkJoin common pool as in the Scala stdlib) when converting to Java | ||
| */ | ||
| object DispatcherFutureConverters { |
There was a problem hiding this comment.
I don't think this should be public API but Akka-internal.
The Scala standard library's conversion from Scala future to Java CompletionStage defines the "non-
Async" versions to effectively call theAsyncversion with the Java commonForkJoinPoolspecified. This subtly conflicts with the common understanding of the difference between the non-Asyncversion, and theAsyncversion, as evidenced by various AI answers:Claude
Copilot
Gemini
The parasitic behavior of the non-
Asyncversion is not desirable for the futures returned by Akka (consider that the future returned from asking a remote actor would run callbacks 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) and running both the common FJP and the default dispatcher may result in far more threads running such tasks than is desirable.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 (those where there's an actor system readily available) are then adapted to use this:
EntityRefs in typed cluster sharding