1
votes

I'm using Plays play.api.mvc.WebSockets in combination with akka.contrib.pattern.DistributedPubSub events and this works fine already.

class SomeSocketActor(out: ActorRef) extends Actor {
    val mediator = DistributedPubSubExtension(context.system).mediator
    mediator ! Subscribe("some_group", self)

    def receive: Actor.Receive = {
      case SubscribeAck(Subscribe("some_group", None, `self`)) =>
        context become ready
    }

    def ready: Actor.Receive = {
      // ...
    }

    override def postStop(): Unit = {
      mediator ! Unsubscribe("some_group", self)
    }
}

Once a socket gets close it sends Unsubscribe. Once the Unsubscribe is received by DistributedPubSubMediator it answers with UnsubscribeAck. However since at that moment (which is after postStop) the actor is stopped already and the UnsubscribeAck is moved Akkas dead letters mailbox and my log is spammed with something like:

Message [akka.contrib.pattern.DistributedPubSubMediator$UnsubscribeAck] from Actor[akka://application/user/distributedPubSubMediator#261175455] to Actor[akka://application/system/websockets/24/handler#325798268] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

I know I could just follow the advice in the log message, but that doesn't seem like good practice. Is there any way to tell the actor inside the postStop method to wait for the UnsubscribeAck before stop?

2

2 Answers

0
votes

Not in the postStop method, that is too late.

But instead of stopping before receiving the UnsubscribeAck you could just become waiting just for the UnsubscribeAck and stop when you receive it (or after some timeout, in case the UnsubscribeAck is never received.

0
votes

This is actually supposed to just work, as DistributedPubSubMediator watches for your actor to be Terminated when you subscribe. In a new project it does work as expected, and the mediator unsubscribes for you, so you may not need to do anything. I'm keeping this answer up as it doesn't do this in my project and it may be affecting other people.

What I'm doing is writing a second actor that is long-lived (you could create it in the controller), and have the WebSocket actor talk to that for managing subscriptions. This way the new actor can pass on unsubscribe messages, then it can receive and ignore the UnsubscribeAck.