scala future seq map case至少有一个不超时

时间:2014-02-15 05:15:10

标签: scala match case settimeout future

我必须分别向10个不同的站点发送10个查询,并在play框架上使用scala代码超时。可能有一些网站在超时窗口内没有返回(对该网站超时的查询)。如果某些站点(至少一个站点)返回响应,我将需要继续进行这些响应。我的代码可以工作,但它非常麻烦。有更好的方法吗?

val timeout = 8.seconds
 Async {
    val resFuture = for {   
       response1 <- Future firstCompletedOf Seq(WS.url1, timeout)
       response2 <- Future firstCompletedOf Seq(WS.url2, timeout)
       response3 <- Future firstCompletedOf Seq(WS.url3, timeout)
       response4 <- Future firstCompletedOf Seq(WS.url4, timeout)
       response5 <- Future firstCompletedOf Seq(WS.url5, timeout)
       response6 <- Future firstCompletedOf Seq(WS.url6, timeout)
       response7 <- Future firstCompletedOf Seq(WS.url7, timeout)
       response8 <- Future firstCompletedOf Seq(WS.url8, timeout)
       response9 <- Future firstCompletedOf Seq(WS.url9, timeout)
       response10 <- Future firstCompletedOf Seq(WS.url10, timeout)
 } yied(response1,response2,response3,response4,response5,response6,response7,response8,response9, response10)

 Future.firstCompletedOf(Seq(resFuture, timeout)).map {
  case: (Some(resp1), Some(resp2),Some(resp3),Some(resp4),Some(resp5),Some(resp6),Some(resp7),Some(resp8),Some(resp9),Some(resp10)) => { process all 10 reponses}
  case: (Some(resp1), Some(resp2),Some(resp3),Some(resp4),Some(resp5),Some(resp6),Some(resp7),Some(resp8),Some(resp9),None) => { process all 9 responses}
  case: (Some(resp1), Some(resp2),Some(resp3),Some(resp4),Some(resp5),Some(resp6),Some(resp7),Some(resp8),None,None) => { process all 8 responses }
  ....
  I will need to enumerate all the possible combinations which will be handres cases. 
 }

}

2 个答案:

答案 0 :(得分:3)

我建议你使用Akka框架的“聚合模式”。使用actor可以减少样板代码。

http://doc.akka.io/docs/akka/snapshot/contrib/aggregator.html

检查文档,有很好的例子,所以我不会在这里复制粘贴它们。 此外,我看到很少有关于此模式的博客条目,但不确定我是否可以在私人博客上发布链接,因此不会将其视为广告。

答案 1 :(得分:0)

我假设WS.urlXFuture[Something]timeoutFuture[Something],将在Y时间后以TimeoutException完成。< / p>

import scala.concurrent._
import ExecutionContext.Implicits.global

val results = Future.sequence(Seq(WS.url1, WS.url2, WS.url3, WS.url4, WS.url5, WS.url6, WS.url7, WS.url8, WS.url9, WS.url10).map(
  // For every of these Futures, fail them if timeout completes first, and lift their result to Some on success and a None on failure
  f => Future.firstCompletedOf(Seq(f, timeout)).map(Some(_)).recover({case _ => None})
))

这将为您提供Future[Seq[Some[Something]]],其中如果元素为Some您在超时内得到了结果,则None如果出现错误或超时。< / p>

现在你可以做到:

for {
  seq <- results
  result <- seq
} result match {
  case Some(r) => doSomethingWith(r)
  case None => doSomethingOnFailure()
}