如何立即通知Akka WebSocket服务器WebSocket客户端已停止

时间:2019-06-03 22:58:52

标签: akka akka-stream akka-http

我正在使用Akka WebSockets进行客户端-服务器通信。

在客户端上:

source
    .viaMat(Http().webSocketClientFlow(httpReq, settings))(Keep.both)
    .toMat(sink)(Keep.both)
    .run()

来源所在的位置

val source = Source.actorRef[Object](Int.MaxValue,OverflowStrategy.fail)

接收器将所有消息转发到ClientActor

在服务器上:

val requestHandler: HttpRequest => HttpResponse = {
      case req @ HttpRequest(GET, Uri.Path("/"), _, _, _) =>
        req.header[UpgradeToWebSocket] match {
          case Some(upgrade: UpgradeToWebSocket) =>

            /**
              * Create an ActorRef for the client. Sending messages to this actor replies to the client.
              * fanout = false, because there is only one output (no broadcasting).
              */
            val source: Source[Object, ActorRef] = Source.actorRef[Object](Int.MaxValue, OverflowStrategy.fail)

            val (clientActor: ActorRef, publisher) = source
              .via(flow)
              .toMat(Sink.asPublisher(fanout = false))(Keep.both).run()

            // receives messages from the client

            val sink: Sink[Message, NotUsed] = Common.getSink(messageHandler, clientActor)

            upgrade.handleMessagesWithSinkSource(sink, Source.fromPublisher(publisher))

          case None =>
            HttpResponse(400, entity = "Not a valid websocket request!")
        }
      case r: HttpRequest =>
        r.discardEntityBytes() // important to drain incoming HTTP Entity stream
        HttpResponse(404, entity = "Unknown resource!")
    }

然后sink将所有消息转发到ServerActor

ServerActor

def receive: PartialFunction[Any, Unit] = {
    case Terminated(sender) =>
      logger.info(s"Detected that client disconnected: $sender")

但是,当我使用clientActor ! PoisonPill停止clientActor时,服务器将花费几分钟的时间来检测到clientActor已断开连接。我需要在clientActor或serverActor中进行哪些更改才能立即检测到断开连接?任何指针都会被应用。

我已经完成调试:

我尝试使用system.context.terminate(),并且ServerActor会立即检测到断开连接,但随后不允许我创建新的ClientActor。我遇到“ Why does Akka fail with "IllegalStateException: cannot create children while terminating or terminated" when testing with ScalaTest?”错误。

我进行了一些挖掘,发现Akka WebSocket使用streamSupervisor演员进行通信,并且clientActorserverActor都在监视这些streamSupervisor演员。

这里的期望是要立即检测到serverActor actor上的客户端断开连接。

1 个答案:

答案 0 :(得分:0)

您可以将Sink.actorRef用于流的接收器。客户端终止连接后,actor将收到此消息,您可以毒害与WebSocket对应的子actor。