在级联Http调用的情况下放置dispatch.Http.shutdown()的位置

时间:2014-02-14 23:58:35

标签: scala future scala-dispatch

Where to put dispatch.Http.shutdown(),如果有dispatch.Http.shutdown()个独立的Http调用,我会询问将呼叫置于n的位置。但是,这些n个独立呼叫都处于同一“级别”。

如何级联Http调用,而outer1outer2彼此独立(就像我以前的问题一样),但内部调用依赖于相应外部呼叫的结果。

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)不会输入检查。

1 个答案:

答案 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,那么使用几个理解几乎可以肯定地做得更多,重复性更少。事实上,我不知道你想在里面做什么。