This is an automated email from the ASF dual-hosted git repository.
He-Pin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko.git
The following commit(s) were added to refs/heads/main by this push:
new acd4926ac1 refactor: use CompletableFuture.orTimeout in
FutureTimeoutSupport (#3137)
acd4926ac1 is described below
commit acd4926ac13b4b496907706832856ad83897ab20
Author: He-Pin(kerr) <[email protected]>
AuthorDate: Tue Jun 23 18:44:30 2026 +0800
refactor: use CompletableFuture.orTimeout in FutureTimeoutSupport (#3137)
* refactor: use CompletableFuture.orTimeout in FutureTimeoutSupport
Motivation:
timeoutCompletionStage was deprecated in favor of
CompletableFuture.orTimeout
but still used a manual Scheduler-based implementation internally.
Modification:
Rewrite timeoutCompletionStage to delegate to CompletableFuture.orTimeout().
Add a handle() wrapper to provide a consistent timeout message across JDK
versions (JDK 25's orTimeout produces a null TimeoutException message,
unlike JDK 17 which included a descriptive message). The Scheduler
parameter is retained for API compatibility but no longer used.
Result:
Simpler implementation with ~5 fewer lines, no Scheduler dependency for
timeout scheduling, and consistent timeout messages across JDK versions.
Tests:
sbt "actor-tests / Test / testOnly org.apache.pekko.pattern.PatternsTest" -
33/33 passed
References:
Refs #3136
* refactor: address review feedback on timeoutCompletionStage
Motivation:
Reviewer pjfanning asked two questions on the PR:
1. Whether the explicit `isDone` fast-path was still needed.
2. The `timeoutMessage` string was being allocated on every call,
even on the success and non-timeout failure paths where it is
never observed.
Modification:
- Document that `CompletableFuture.orTimeout` already short-circuits
on already-completed stages, so no explicit `isDone` check is
required.
- Inline the timeout message construction into the
`case _: TimeoutException` branch so it is only allocated when
the stage actually times out.
Result:
Lower per-call allocation on the common (success) path and an
explicit comment clarifying the isDone semantics for future readers.
Tests:
sbt "actor/compile" -- passed
References:
PR #3137 review comments by @pjfanning
---
.../pekko/pattern/FutureTimeoutSupport.scala | 28 ++++++++++------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git
a/actor/src/main/scala/org/apache/pekko/pattern/FutureTimeoutSupport.scala
b/actor/src/main/scala/org/apache/pekko/pattern/FutureTimeoutSupport.scala
index 52709500f6..787adf00bb 100644
--- a/actor/src/main/scala/org/apache/pekko/pattern/FutureTimeoutSupport.scala
+++ b/actor/src/main/scala/org/apache/pekko/pattern/FutureTimeoutSupport.scala
@@ -134,23 +134,19 @@ trait FutureTimeoutSupport {
catch {
case NonFatal(t) => CompletableFuture.failedStage(t)
}
- if (stage.toCompletableFuture.isDone) {
- stage
- } else {
- val p = new CompletableFuture[T]
- val timeout = using.scheduleOnce(duration,
- () => {
- p.completeExceptionally(new TimeoutException(s"Timeout of $duration
expired"))
- stage.toCompletableFuture.cancel(true)
- ()
- })
- stage.handle[Unit]((v: T, ex: Throwable) => {
- timeout.cancel()
- if (v != null) p.complete(v)
- if (ex ne null) p.completeExceptionally(ex)
+ val millis = if (duration.isZero || duration.isNegative) 0L else
duration.toMillis
+ // Note: no explicit `isDone` fast-path is needed here because
+ // `CompletableFuture.orTimeout` already short-circuits on an
already-completed stage.
+ stage.toCompletableFuture
+ .orTimeout(millis, java.util.concurrent.TimeUnit.MILLISECONDS)
+ .handle((v: T, ex: Throwable) => {
+ if (ex ne null) {
+ ex match {
+ case _: TimeoutException => throw new TimeoutException(s"Timeout
of $duration expired")
+ case _ => throw ex
+ }
+ } else v
})
- p
- }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]