Skip to content

Instantly share code, notes, and snippets.

@takezoe
Last active August 29, 2015 14:12
Show Gist options
  • Save takezoe/173d3fcfe50e7714ec90 to your computer and use it in GitHub Desktop.
Save takezoe/173d3fcfe50e7714ec90 to your computer and use it in GitHub Desktop.
Futureの練習問題です

Futureの待ち合わせ

以下のような2つのクラスタを構成するサーバの一覧があるとします。

val cluster1 = Seq("server1", "server2")
val cluster2 = Seq("server3", "server4")

これらのサーバに対してFutureを使って以下のような処理を非同期で行うプログラムを書いてみよう。

  1. すべてのサーバに対してhttp://<サーバ名>/restoreというリクエストを非同期に送信
  2. クラスタ単位で処理が終わったら当該クラスタのサーバにhttp://<サーバ名>/activateリクエストを送信

リクエストの送信にはDispatchを使うと以下のように記述できます。

import dispatch._, Defaults._

def post(endpoint: String): Future[Either[Throwable, String]] = {
  val request = url(endpoint).POST
  Http(request OK as.String).either
}

すぐに思いつくのは以下のような感じ。

Seq(cluster1, cluster2).foreach { cluster =>
  // restoreリクエストを送信
  cluster.map { server =>
    post(s"http://${server}/restore")
  }.map(Await.result(_, Duration.Inf)) // 待ち合わせ
  
  // activateリクエストを送信
  cluster.foreach { server =>
    post(s"http://${server}/activate")
  }
}

途中でAwait.resultするのはダサいよねーということでこんな感じに。Future.sequence()を使うとFutureのシーケンスから1つのFutureを作ることができる。

Seq(cluster1, cluster2).foreach { cluster =>
  Future.sequence(
    // restoreリクエストを送信
    cluster.map { server =>
      post(s"http://${server}/restore")
    }
  ).map { _ =>
    // activateリクエストを送信
    cluster.map { server =>
      post(s"http://${server}/activate")
    }
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment