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]

Reply via email to