我目前正在使用Akka actor,streaming和http的组合来处理客户端告诉服务器接收事件的速度有多快的情况,并且服务器以该速率发送客户端事件。 / p>
这是发送给服务器的客户端消息:
{
"uuid": "d30711c6-6bbf-4f11-9471-638ef7e19dfd",
"startTime": "1501254050",
"rate": "1.5"
}
这是一条如下所示的路线:
path("ws") { // /ws path allows websocket connections
get {
extractUpgradeToWebSocket { upgrade =>
complete(upgrade.handleMessagesWithSinkSource(replaySink, Source.maybe))
}
}
}
replaySink
只是将JSON解析为一个case类,它使用以下命令发送给一个主管actor:
val replaySupervisor = system.actorOf(ReplaySupervisor.props(), "replay-supervisor")
val replaySink: Sink[Message, NotUsed] = Flow[Message]
.map{
case tm: TextMessage.Strict =>
val msgJson = parse(tm.getStrictText).getOrElse(Json.Null)
msgJson.as[ReplayRequest].getOrElse("JSONParsingError")
case _ => log.error("Incoming message not in proper format")
}
.to(Sink.actorRefWithAck(
ref = replaySupervisor,
onInitMessage = InitMessage,
ackMessage = AckMessage,
onCompleteMessage = ConnectionClosed
)
)
只有在WebSocket连接超时后才会发送ConnectionClosed
消息,因为它实际上是一个无限制的来源。
当主管收到消息时,它会创建新的子actor,为其提供客户端提供的UUID,然后传递消息。或者如果孩子已经存在(因为客户端必须通过定期发送相同的事件来保持连接打开,或者因为它改变了开始时间/速率并发送了新消息),所以它只是传递它。
我的问题是,一旦连接关闭,我该如何告诉儿童演员停止?上面的接收器不知道哪个子actor最终收到它的消息,所以我不能发送带有UUID的ConnectionClosed消息让主管转发告诉子actor停止自己。发送PoisonPill只会杀死主管。我能想到的最好的方法是使用set的子节点的ReceiveTimeout属性在一段时间内没有收到事件后自行停止,并让客户端发送常规消息。
是否有一种更优雅的方式来做到这一点,但是当连接关闭时会停止演员呢?
答案 0 :(得分:0)
当Sink.actorRef
具体化时,它会在内部创建一个actor,这个actor将成为你演员的消息的发送者。
您可以使用ActorRef
中的发件人InitMessage
以及为该发件人创建的子项在主管中保留地图。当您获得ConnectionClosed
(或Failed
正在运行失败时),发件人将是相同的,您可以查找正确的孩子并将其关闭。
另一种选择可能是在路线中生成唯一ID(例如UUID),并提供InitMessage(id)
和ConnectionClosed(id)
。