Futures patterns

Dependency

Pekko offers tiny helpers for use with FuturesCompletionStage. These are part of Pekko’s core module:

sbt
val PekkoVersion = "1.0.0"
libraryDependencies += "org.apache.pekko" %% "pekko-actor" % PekkoVersion
Maven
<properties>
  <scala.binary.version>2.13</scala.binary.version>
</properties>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.pekko</groupId>
      <artifactId>pekko-bom_${scala.binary.version}</artifactId>
      <version>1.0.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>
<dependencies>
  <dependency>
    <groupId>org.apache.pekko</groupId>
    <artifactId>pekko-actor_${scala.binary.version}</artifactId>
  </dependency>
</dependencies>
Gradle
def versions = [
  ScalaBinary: "2.13"
]
dependencies {
  implementation platform("org.apache.pekko:pekko-bom_${versions.ScalaBinary}:1.0.0")

  implementation "org.apache.pekko:pekko-actor_${versions.ScalaBinary}"
}

After

org.apache.pekko.pattern.afterorg.apache.pekko.pattern.Patterns.after makes it easy to complete a FutureCompletionStage with a value or exception after a timeout.

Scala
sourceval delayed =
  pekko.pattern.after(200.millis)(Future.failed(new IllegalStateException("OHNOES")))

val future = Future { Thread.sleep(1000); "foo" }
val result = Future.firstCompletedOf(Seq(future, delayed))
Java
source
CompletionStage<String> failWithException = CompletableFuture.supplyAsync( () -> { throw new IllegalStateException("OHNOES1"); }); CompletionStage<String> delayed = Patterns.after(Duration.ofMillis(200), system, () -> failWithException);

Retry

org.apache.pekko.pattern.retryorg.apache.pekko.pattern.Patterns.retry will retry a FutureCompletionStage some number of times with a delay between each attempt.

Scala
sourceimport org.apache.pekko
import pekko.actor.typed.scaladsl.adapter._
implicit val scheduler: pekko.actor.Scheduler = system.scheduler.toClassic
implicit val ec: ExecutionContext = system.executionContext

// Given some future that will succeed eventually
@volatile var failCount = 0
def futureToAttempt() = {
  if (failCount < 5) {
    failCount += 1
    Future.failed(new IllegalStateException(failCount.toString))
  } else Future.successful(5)
}

// Return a new future that will retry up to 10 times
val retried: Future[Int] = pekko.pattern.retry(() => futureToAttempt(), attempts = 10, 100 milliseconds)
Java
source
Callable<CompletionStage<String>> attempt = () -> CompletableFuture.completedFuture("test"); CompletionStage<String> retriedFuture = Patterns.retry(attempt, 3, java.time.Duration.ofMillis(200), system);