如何实现对支持异步回调的方法的调用的限制

时间:2017-04-12 15:28:03

标签: scala akka akka-stream

假设我们有从Future[T]返回CompletableFuture[T]或java AsyncCompletionHandler[T]或自定义org.asynchttpclient的方法。我想限制对这种方法的所有调用。

你会怎么做?目前,我使用基于MergeHub.source的{​​{1}}来汇总所有请求。问题我有

  1. 有更好的方法吗?
  2. 在我的日志输出中,我看到花在所有请求上的时间少于我的预期。为什么?
  3. 这是代码

    Sink

    换句话说,有多个地方,如主要的内容。所有这些都应该作为呼叫总和的限制。

1 个答案:

答案 0 :(得分:1)

作为一般性评论,您可能没有MergeHub步骤并简化您的管道。见下面的例子

object Main {

  private implicit val system = ActorSystem("root")
  private implicit val executor = system.dispatcher
  private implicit val mat = ActorMaterializer(ActorMaterializerSettings(system))

  def makeRequest(url: String): Future[Response] = {
    val promise = Promise[Response]()
    asyncHttpClient.prepareGet(url).execute(new AsyncCompletionHandler[Response] {
      def onCompleted(response: Response) = {
        promise.success(response)
        response
      }
      override def onThrowable(t: Throwable) {
        promise.failure(t)
        super.onThrowable(t)
      }
    })
    promise.future
  }

  val asyncHttpClient = new DefaultAsyncHttpClient()

  def main(args: Array[String]): Unit = {

    val start = ZonedDateTime.now()
    println("Start!")
    Source(1 to 20)
      .throttle(1, FiniteDuration(2000, MILLISECONDS), 1, ThrottleMode.Shaping)
      .mapAsync(4) { index =>
        println(s"${ZonedDateTime.now().toEpochSecond - start.toEpochSecond} s - Requesting $index")
        makeRequest(s"http://httpbin.org/get?param=$index").map { r =>
          println(s"${ZonedDateTime.now().toEpochSecond - start.toEpochSecond} s - Got $index - Code ${r.getStatusCode}")
        }
      }
      .runWith(Sink.ignore)
      .onComplete {
        case Success(_) =>
          println(s"${ZonedDateTime.now().toEpochSecond - start.toEpochSecond} Done!")
          asyncHttpClient.close()
          system.terminate()
        case Failure(ex) =>
          ex.printStackTrace()
          asyncHttpClient.close()
          system.terminate()
      }

    Await.result(system.whenTerminated, Duration.Inf)
  }
}

然而,在两种实现中,我都看到请求被正确限制 - 每2秒一次,大致从第二次〜0次到第二次~38次。

你能详细说明你对这里的期望吗?