ScalaのFutureがブロックする?(深く調べてない)

ScalaのFutureで(あるいはPlay?)で処理がブロックされてしまう現象があった。

環境

  • Scala 2.10.1
  • Play 2.1.3
  • (Playのモデルクラスを使っているだけで、scalaコマンドから起動されるバッチ処理)

簡略化するとこんなコード(実際はもっと分割されてるし、whileじゃなくてtailrecだけど)。

import scala.concurrent.Await
import scala.concurrent.duration._
import play.api.libs.concurrent.Execution.Implicits._
 
for {
  photo <- listOfPhotos
} yield {
  // downloadはサードパーティライブラリのメソッドで
  // Future[java.io.File]を返す
  val fut = photo.download map { file =>
    Logger.debug("start!") //ここまでは実行される。
    // SomeApi.postFileの挙動は、responseが返るまでブロックする。
    // しかし、↓が実行されない
    SomeApi.postFile(file) map { jobId =>
      var complete = false
      var result = None
      while (!complete) {
        Thread.sleep(5000)
        val job = SomeApi.getJob(jobId)
        if (job.isComplete()) {
          complete = true
          result = job.getResult()
          // resultに対して処理
        }
      }
    }
  }
  try {
    Await.result(fut, 120 seconds)
  } catch {
    case e: Exception => Logger.error(e.getMessage())
  }
}

とりあえずの解決策

Futureに関する理解が甘かったので、勉強しつつ色々調べたんだけど、根本的な原因は良く分からなかった。でも、とりあえずの解決策が見つかった。以下のように、ExecutionContextを変えること。

//import play.api.libs.concurrent.Execution.Implicits._ //コメントアウトして
import scala.concurrent.ExecutionContext.Implicits.global //こっちを追加

Playのバグなのか、自分のコードが悪いのか・・・そのうちPlay 2.2にアップグレードする予定なので、そしたら再度試してみよう。

(追記)Play! 2.2では直ってた

Play! 2.2にアップグレードしたところ、問題は解消した。

自分用メモ

Futureについて

直列で実行

複数のFutureの実行方法色々

“ScalaのFutureがブロックする?(深く調べてない)” への3件の返信

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です