Scala 为什么Source.tick会在100次HttpRequests之后停止?
使用akka stream和akka HTTP,我创建了一个流,它每3秒轮询一个api,将结果解组到JsValue对象,并将结果发送给参与者。如以下代码所示: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
// 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
是一种改进。