18
16

More than 5 years have passed since last update.

ScalaのFutureでタイムアウトしたい時はAkkaを使う

Posted at

非同期処理を書くときにFuture/Promiseパターンは便利です。C++11とかEcmaScript6とか様々な言語に浸透した感があって、もちろんScalaにもあります。

さて、ScalaのFutureに後からタイムアウトを付けたい場合は、標準でAwait.result[T](awaitable: Awaitable[T], atMost: Duration)が用意されていて、複数のFutureを一斉に待ちあわせたい時はfor内包表記(yield使うやつ)で合成しておけば良さそうです。モナド……!
が、この合成は元のFutureが一つでも失敗すると全体的に失敗してしまうので、Futureそれぞれで成功したものは結果を取得したいし失敗したときはデフォルト値にしておきたい、といった場合だと単純には使えません。

で、どうするんだろうと思ったらやはり同様の質問があって、

Akkaライブラリのakka.pattern.afterを使う回答があります。

implicit class FutureHelper[T](f: Future[T]) extends AnyVal{
  import akka.pattern.after
  def orDefault(t: Timeout, default: => T)(implicit system: ActorSystem): Future[T] = {
    val delayed = after(t.duration, system.scheduler)(Future.successful(default))
    Future firstCompletedOf Seq(f, delayed)
  }
}

implicit classなのでFutureから直接orDefaultを呼びだせる(ように書ける)というわけですね。便利!
defaultが名前渡しなのはafter[T](duration: FiniteDuration, using: Scheduler)(value: ⇒ Future[T])に合わせて、タイムアウト時をカウントする前にデフォルト値の評価時間を食わないためですね。

この手法の利点は解説記事があって、

Akkaのドキュメントにも載っています。

18
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
16