Scala 为什么Source.tick会在100次HttpRequests之后停止?

Scala 为什么Source.tick会在100次HttpRequests之后停止?,scala,akka,akka-http,Scala,Akka,Akka Http,使用akka stream和akka HTTP,我创建了一个流,它每3秒轮询一个api,将结果解组到JsValue对象,并将结果发送给参与者。如以下代码所示: // Source wich performs an http request every 3 seconds. val source = Source.tick(0.seconds, 3.seconds, HttpRequest(uri

使用akka stream和akka HTTP,我创建了一个流,它每3秒轮询一个api,将结果解组到JsValue对象,并将结果发送给参与者。如以下代码所示:

// Source wich performs an http request every 3 seconds.
val source = Source.tick(0.seconds,
                         3.seconds,
                         HttpRequest(uri = Uri(path = Path("/posts/1"))))

// Processes the result of the http request
val flow = Http().outgoingConnectionHttps("jsonplaceholder.typicode.com").mapAsync(1) {

  // Able to reach the API.
  case HttpResponse(StatusCodes.OK, _, entity, _) =>
    // Unmarshal the json response.
    Unmarshal(entity).to[JsValue]

  // Failed to reach the API.
  case HttpResponse(code, _, entity, _) =>
    entity.discardBytes()
    Future.successful(code.toString())


}

// Run stream
source.via(flow).runWith(Sink.actorRef[Any](processJsonActor,akka.actor.Status.Success(("Completed stream"))))
这是可行的,但是流在100次HttpRequests(滴答声)后关闭


这种行为的原因是什么

肯定与
outgoingConnectionHttps
有关。这是一个低水平的DSL,可能是由于某些地方的配置错误造成的(尽管我不知道是哪一个)

实际上,用户不鼓励使用此DSL

尝试使用更高级别的DSL,如缓存连接池

  val flow = Http().cachedHostConnectionPoolHttps[NotUsed]("akka.io").mapAsync(1) {

    // Able to reach the API.
    case (Success(HttpResponse(StatusCodes.OK, _, entity, _)), _) =>
      // Unmarshal the json response.
      Unmarshal(entity).to[String]

    // Failed to reach the API.
    case (Success(HttpResponse(code, _, entity, _)), _) =>
      entity.discardBytes()
      Future.successful(code.toString())

    case (Failure(e), _) ⇒
      throw e
  }

  // Run stream
  source.map(_ → NotUsed).via(flow).runWith(...)

一个潜在的问题是,
Sink.actorRef
没有背压信号,因此参与者的邮箱可能已满。如果参与者在收到
JsValue
对象时正在做一些可能需要很长时间的事情,请使用。例如:

val initMessage = "start"
val completeMessage = "done"
val ackMessage = "ack"

source
  .via(flow)
  .runWith(Sink.actorRefWithAck[Any](
    processJsonActor, initMessage, ackMessage, completeMessage))

您需要更改参与者以处理
initMessage
,并使用
ackMessage
(使用
sender!ackMessage
)为每个流元素回复流。找到了有关Sink.actorRefWithAck的更多信息。

这解决了问题。至于
outgoingConnectionHttps
,可能是实体没有完全消耗导致背压,这就是它停止的原因吗?流肯定是背压,所以这也是我的第一个想法。但是,即使是最简单的流(
Http().outgoingConnection(“jsonplaceholder.typicode.com”).map(uu.discardEntityBytes())
)也会有效地丢弃所有实体,问题仍然存在。我更倾向于认为这是由埋在某处的某个环境造成的,甚至可能是一个bug……这不是问题所在。尽管如此,与我发布的代码相比,使用
Sink.actorref
是一种改进。