在Where to put dispatch.Http.shutdown(),如果有dispatch.Http.shutdown()
个独立的Http调用,我会询问将呼叫置于n
的位置。但是,这些n
个独立呼叫都处于同一“级别”。
如何级联Http调用,而outer1
和outer2
彼此独立(就像我以前的问题一样),但内部调用依赖于相应外部呼叫的结果。
val outer1 = dispatch.Http(... request1 ...)
val outer2 = dispatch.Http(... request2 ...)
outer1 onComplete {
case Success(h) =>
/*inner11*/ dispatch.Http(... request11 based on `h` ...) onComplete { ... }
/*inner12*/ dispatch.Http(... request12 based on `h` ...) onComplete { ... }
case Failure(e) => logger.debug(s"Error: $e")
}
outer2 onComplete {
case Success(j) =>
/*inner21*/ dispatch.Http(... request21 based on `j` ...) onComplete { ... }
/*inner22*/ dispatch.Http(... request22 based on `j` ...) onComplete { ... }
case Failure(e) => logger.debug(s"Error: $e")
}
dispatch.Future.sequence(outer1 :: outer2 :: Nil) onComplete {
case _ => dispatch.Http.shutdown() // <<<<< too early
}
谢谢,/ nm
更新1:感谢Kevin Wright,事情变得越来越清晰。在下文中,我试图澄清为什么我需要这个级联的未来和嵌套的onComplete。假设我想获得经过身份验证的用户的所有可访问GitHub存储库的URL列表:
object Main extends App with Logging {
import scala.concurrent.ExecutionContext.Implicits.global
def logFailure[T](f: Future[T]) =
f onFailure { case x => logger.debug("Error: " + x.toString) }
// Personal access token
val pat = "..."
// GitHub API
val github: Req = host("api.github.com").secure
// Http executor
//val http = Http()
// User profile of authenticated user
val ur: Req = github / "user" <:< Map("Authorization" -> s"token $pat")
// Retrieve *all* accessible repositories for authenticated user
Http(ur OK as.json4s.Json) flatMap { u =>
// organizations' repos
val inner1 = (u \ "organizations_url").toOption collect { case JString(org) =>
Http(url(org) OK as.json4s.Json) flatMap { o =>
(o \ "repos_url").toOption collect { case JString(rep) =>
Http(url(rep) OK as.json4s.Json) map { _ \ "html_url" }
}
}
}
// user's repos
val inner2 = (u \ "repos_url").toOption collect { case JString(usr) =>
Http(url(usr) OK as.json4s.Json) map { _ \ "html_url" }
}
???
}
}
然后,只要我检索了所有网址,我就想为每个网址生成一个git clone
进程。
不幸的是inner1
还没有输入检查。而且,如果inner1: Option[Future[JValue]]
和inner2: Option[Future[JValue]]
,则Future.sequence(inner1 :: inner2 :: Nil)
不会输入检查。
答案 0 :(得分:0)
如果将成功和失败路径分开,您会发现事情变得更容易。
import dispatch.Future
def logFailure[T](f: Future[T]) =
f onFailure { case x => logger.debug("Error: " + x.toString) }
val outer1 = dispatch.Http(... request1 ...) flatMap { h =>
val in1 = dispatch.Http(... request11 based on `h` ...)
val in2 = dispatch.Http(... request12 based on `h` ...)
in1 onComplete { ... }
in2 onComplete { ... }
Future.sequence(in1:: in2 :: Nil)
}
val outer2 = dispatch.Http(... request2 ...) flatMap { j =>
val in1 = dispatch.Http(... request21 based on `j` ...)
val in2 = dispatch.Http(... request22 based on `j` ...)
in1 onComplete { ... }
in2 onComplete { ... }
Future.sequence(in1:: in2 :: Nil)
}
logFailure(outer1)
logFailure(outer2)
Future.sequence(outer1 :: outer2 :: Nil) onComplete {
case _ => dispatch.Http.shutdown() // <<<<< too early
}
如果不是那些嵌套操作的onComplete
,那么使用几个理解几乎可以肯定地做得更多,重复性更少。事实上,我不知道你想在里面做什么。