Peltevis
Peltevis

Reputation: 15

Timeout a Future in Scala.js

I need to place a timeout on a Future in a cross-platform JVM / JS application. This timeout would only be used in tests, so a blocking solution wouldn't be that bad.

I implemented the following snippet to make the future timeout on JVM:

  def runWithTimeout[T](timeoutMillis: Int)(f: => Future[T]) : Future[T] =
      Await.ready(f, Duration.create(timeoutMillis, java.util.concurrent.TimeUnit.MILLISECONDS))

This doesn't work on Scala.js, as it has no implementation of Await. Is there any other solution to add a Timeout to a Future that works in both Scala.js and Scala JVM?

Upvotes: 0

Views: 303

Answers (1)

sjrd
sjrd

Reputation: 22095

Your code doesn't really add a timeout to the existing future. That's not possible. What you're doing is setting a timeout for waiting for that future at that specific point. That, you can reproduce in a different, fully asynchronous way, by creating a future that will

  • resolve to f if it finishes within the given timeout
  • otherwise resolves to a failed TimeoutException
import scala.concurrent._
import scala.concurrent.duration.Duration

import scala.scalajs.js

def timeoutFuture[T](f: Future[T], timeout: Duration)(
    implicit ec: ExecutionContext): Future[T] = {
  val p = Promise[T]()
  val timeoutHandle = js.timers.setTimeout(timeout) {
    p.tryFailure(new TimeoutException)
  }
  f.onComplete { result =>
    p.tryComplete(result)
    clearTimeout(timeoutHandle)
  }
  p.future
}

The above is written for Scala.js. You can write an equivalent one for the JVM, and place them in platform-dependent sources.

Alternatively, you can probably write something equivalent in terms of java.util.Timer, which is supported both on JVM and JS.

Upvotes: 2

Related Questions