简体   繁体   中英

How to subscribe actors into akka event bus automatically in Play2.4/Scala

I am starting to dive into AKKA/Event Bus and related...

I created a small test actor as follows:

class TestActor extends Actor with ClassLogger{


    @throws[Exception](classOf[Exception])
    override def preStart(): Unit = {
        context.system.eventStream.subscribe(context.self, classOf[FormFieldValue])
    }

    override def receive = {
        case (v: FormFieldValue) => logger.info("Value received: " + v.fieldValue)
        case _ => logger.info("Something unknown")
    }
}

and trying to publish an event from another part of an application:

system.eventStream.publish(updatedValue)

Everything compiles and works as it used to, and nothing been logged. Basically, the actor is not been called.

Now, I also tried to create a module that will register all the subscribers, like so:

class EventsRegistry @Inject()(system: ActorSystem) extends AbstractModule {

    override def configure(): Unit = {
        val testListeener = system.actorOf(Props(classOf[TestActor]))

        system.eventStream.subscribe(testListeener, classOf[FormFieldValue])
    }
}

And configured the module in application.conf:

play.modules.enabled  += "events.modules.EventsRegistry"

and removed preStart from Actor.

And now I am getting an error:

lay.api.PlayException: No valid constructors[Module [events.modules.EventsRegistry] cannot be instantiated.]

What am I doing wrong?

Update the only way I got that working is by setting up subscriber in Global#onStart:

override def onStart(app: play.api.Application) {

        val testListeener = Akka.system.actorOf(Props(classOf[TestActor]))

        Akka.system.eventStream.subscribe(testListeener, classOf[FormFieldValue])

    }

But usage of GlobalSettings is deprecated....

To make it work you need to decouple the Registry and the Module.

package actors
import akka.actor._
import com.google.inject._
import play.api.inject.ApplicationLifecycle

import scala.concurrent.Future

case class FormFieldValue(fieldValue: String)

class TestActor extends Actor with ActorLogging {

  @throws[Exception](classOf[Exception])
  override def preStart(): Unit = {
    context.system.eventStream.subscribe(context.self, classOf[FormFieldValue])
    super.preStart()
  }

  @throws[Exception](classOf[Exception])
  override def postStop(): Unit = {
    context.system.eventStream.unsubscribe(context.self)
    super.postStop()
  }

  override def receive = {
    case (v: FormFieldValue) => log.info("Value received: " + v.fieldValue)
    case _ => log.info("Something unknown")
  }
}

@Singleton
class EventBusLifeCycle @Inject()(system: ActorSystem, lifecycle: ApplicationLifecycle) {
  val testListener = system.actorOf(Props(classOf[TestActor]))

  lifecycle.addStopHook { () =>
    Future.successful(system.stop(testListener))
  }

}

class EventBusModule extends AbstractModule {
  def configure() = {
    bind(classOf[EventBusLifeCycle]).asEagerSingleton()
  }
}

And register the module in application.conf

play.modules.enabled += "actors.EventBusModule"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM