ActorSystem singleton injection - scala

In my project, I have to use actors and schedulers. All my need can be accomplished by using one actor system only. But I need the schedulers and actors in more than one class. So my question, if I should inject the actor system in each class like below, will it create only one actor System or more than one? I don't want to create more than one actor system since it is not a recommended practice.
import akka.actor.ActorSystem
#Singleton
class someClass #Inject()(actorSystem: ActorSystem){....} // abstract class ActorSystem extends ActorRefFactory
#Singleton
class anotherClass #Inject()(actorSystem: ActorSystem){....}
Or I should create another object and declare an actor system within it and use it everywhere like this:
import akka.actor._
object actorSystemObject {
val system: ActorSystem = ActorSystem()
}
Which method will be better and standard?

Assuming you are using guice, try providing a singleton like so
#Provides
#Singleton
def getActorSystem: ActorSystem = ActorSystem()
for example
import akka.actor.ActorSystem
import com.google.inject.{AbstractModule, Guice, Inject, Injector, Provides, Singleton}
import scala.jdk.CollectionConverters._
class MyModule extends AbstractModule {
#Provides
#Singleton
def getActorSystem: ActorSystem = ActorSystem()
}
#Singleton
class SomeClass #Inject()(actorSystem: ActorSystem) {
println(actorSystem.hashCode())
}
#Singleton
class SomeOtherClass #Inject()(actorSystem: ActorSystem) {
println(actorSystem.hashCode())
}
object Hello extends App {
val injector: Injector = Guice.createInjector(List(new MyModule).asJava)
injector.getInstance(classOf[SomeClass])
injector.getInstance(classOf[SomeOtherClass])
}
which outputs something like
1731656333
1731656333
where we see the same ActorSystem is injected as evident by the same hashCode.
Say we remove #Singleton provider like so
#Provides
def getActorSystem: ActorSystem = ActorSystem()
then hashCodes differ, for example,
2050462663
1117871068

Related

How do I access the actor system used in Play 2.5 from within a Module

I need access to the default actor system that Play Framework 2.5 uses from within my Module class.
I see that there is a method on ActorSystemProvider to get this:
#Singleton
class ActorSystemProvider #Inject()(environment: Environment, configuration: Configuration, applicationLifecycle: ApplicationLifecycle) extends Provider[ActorSystem] {
private val logger = Logger(classOf[ActorSystemProvider])
lazy val get: ActorSystem = {
val (system, stopHook) = ActorSystemProvider.start(environment.classLoader, configuration)
applicationLifecycle.addStopHook(stopHook)
system
}
}
But how do I get access to this class in my Module class?
For example:
class Module extends AbstractModule {
val playSystem: ActorSytem = ???
...
}
You can access actorSystem by simply injecting it into any of the component constructor. You will get access to the actorSystem created by play and you need not do any of the provider gymnastics.
For example, I need actor system to be accessible in my HomeController. So, I just inject into my HomeController constructor.
class HomeController #Inject() (actorSystem: ActorSystem) extends Controller {
def index = Ok("bye!")
}

Illegal inheritance, superclass X not a subclass of the superclass Y of the mixin trait Z - Scala

I am trying to execute a akka-http which is a scala program. My KISS code is as follows:-
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, HttpResponse}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.BasicDirectives
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Flow
import com.typesafe.config.ConfigFactory
object MyBoot02 extends SprayCanBoot02 with RestInterface02 with App {
}
abstract class SprayCanBoot02 {
val config = ConfigFactory.load()
val host = config.getString("http.host")
val port = config.getInt("http.port")
implicit val system = ActorSystem("My-ActorSystem")
implicit val executionContext = system.dispatcher
implicit val materializer = ActorMaterializer()
//implicit val timeout = Timeout(10 seconds)
implicit val routes: Flow[HttpRequest, HttpResponse, Any]
Http().bindAndHandle(routes, host, port) map {
binding => println(s"The binding local address is ${binding.localAddress}")
}
}
trait RestInterface02 extends AncileDemoGateway02 with Resource02 {
implicit val routes = questionroutes
val buildMetadataConfig = "this is a build metadata route"
}
trait Resource02 extends QuestionResource02
trait QuestionResource02 {
val questionroutes = {
path("hi") {
get {
complete("questionairre created")
}
}
}
}
class AncileDemoGateway02 {
println("Whatever")
}
The error that I get is because of how I am wiring stuff when trying to execute MyBoot02. The error is as follows:
Error:(58, 41) illegal inheritance; superclass SprayCanBoot is not a
subclass of the superclass AncileDemoGateway of the mixin trait
RestInterface object MyBoot extends SprayCanBoot with RestInterface
with App
Why does the error state 'SprayCanBoot is not a subclass of the superclass AncileDemoGateway'. In my code SprayCanBoot and AncileDemoGateway are 2 separate entities then why such an error?
Thanks
Unfortunately, for some mysterious reason, that's probably inherited from the wonderful design of Java, you cannot extend more than one class either directly or indirectly.
It is possible to mix in as many traits as you want, but you can only have one superclass in the hierarchy (ok, technically, you can have more than one, but they all must be extending each other - that's why your error message is complaining about SprayBoot not being a subclass).
In your case, you are extending SprayCanBoot02, which is a class, and also RestInterface02, that extends AncileDemoGateway02, which is also a class. So MyBoot02 is trying to extend two different classes at once, which is illegal.
Making AncileDemoGateway02 a trait should fix the error.
In general, a trait inheriting from a class is commonly used to limit the classes a trait can be mixed into.
In your case, the MyBoot02 class can’t extend the RestInterface02 trait, because MyBoot02 and RestInterface02 don’t share the same superclass.

Accessing Play configuration from Akka Actor

I have an Akka Actor in my Play app that accesses Play's configuration using a now deprecated method.
class MyActor (supervisor: ActorRef) extends Actor {
val loc = Play.current.configuration.getString("my.location").get
def receive = { case _ => }
}
if I do this:
import javax.inject._
class MyActor #Inject(configuration: play.api.Configuration) (supervisor: ActorRef) extends Actor {
My class won't compile and the compler returns: "classfile annotation arguments have to be supplied as named arguments"
I assume you can only DI the configuration within a controller class. So, is it possible to access the configuration from within an Akka Actore within a Play app? I could pass the configuration to the actor during construction or just have a separate config file for the actors, but both seem pretty hacky. Is there a preferred method using the Play api?
Thanks!
The answer by mana above points out the most elegant way to use DI in combination with actors in Play, but within any Actor you can find the configuration like:
context.system.settings.config
This is working in my project:
Module.scala:
class ExampleModule extends AbstractModule with AkkaGuiceSupport {
override def configure(): Unit = {
bindActor[ExampleActor]("example-actor-name")
}
}
Actor.scala:
object ExampleActor {
def props = Props[ExampleActor]
}
#Singleton
class ExampleActor #Inject()(/*some DI*/) extends Actor {
...
}
And you can then even inject that very actor into other Classes (the #Named() is optional if you have only one Actor configured) via DI:
SomeOtherClass.scala
#Singleton
class SomeOtherClass #Inject()(#Named("example-actor-name") exampleActor: ActorRef) {
...
}

Eagerly initialize singleton actor in scalaguice

I would like to eagerly initialize a singleton actor. I currently do the below and then later in my app startup get the instance of the actor.
`bind[Actor].annotatedWith(Names.named(LockCoordinator.name)).to[LockCoordinator].in[Singleton]`
I have tried
bind[Actor].annotatedWith(Names.named(LockCoordinator.name)).to[LockCoordinator].asEagerSingleton()
but fails at runtime with
1) Error injecting constructor, akka.actor.ActorInitializationException: You cannot create an instance of [LockCoordinator] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
I do create an eagerSingleton already for the system, but couldn't figure out how to apply it for an Actor (not ActorRef)
class ActorSystemProvider #Inject() (val config: Config, val injector: Injector) extends Provider[ActorSystem] {
override def get() = {
val system = ActorSystem(config.getString("mysystem"), config)
GuiceAkkaExtension(system).initialize(injector)
system
}
}
Is there a boilerplate free way of achieving this? As I want to apply this to 3-4 other actors
Does this help?
https://gist.github.com/fancellu/e4e8acdc3d7fd3b9d749352f9d6c68e3
import actors.ActorBrowserActor
import com.google.inject.AbstractModule
import play.api.libs.concurrent.AkkaGuiceSupport
class Module extends AbstractModule with AkkaGuiceSupport{
def configure(): Unit = {
bindActor[ActorBrowserActor](ActorBrowserActor.NAME, _=>ActorBrowserActor.props)
}
}
here we inject the actor by name
class SampleController #Inject()(implicit system: ActorSystem, val messagesApi: MessagesApi, #Named("actor-browser-actor") actorBrowserActor: ActorRef)
extends Controller with I18nSupport{
}

Instantiating Akka actors in a Play application with Subcut

I have a Play 2.1 application. I am also using Subcut for dependency injection, which is already set up and working for most parts of the application, except for one.
Say I have the following snippet of actor-related code:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
class FoobarActor extends Actor {
def receive = {
// do stuff here
}
}
object Foobar {
val actor = Akka.system.actorOf(Props[FoobarActor])
}
Now, say I would like to inject some objects into each instance of the FoobarActor using Subcut. This would require the actor class to extend Injectable, with the BindingModule passed into the constructor, like this:
import akka.actor._
import com.typesafe.plugin._
import play.api.Play.current
import play.api.libs.concurrent.Akka
import com.escalatesoft.subcut.inject.{Injectable, BindingModule}
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
The question is: how is such an actor instantiated?
Typically, objects managed by Subcut are constructed in Subcut's configuration objects (i.e., objects that extend NewBindingModule), or in the case of Play's controllers, in the Global object (see play-subcut on github).
What would I replace Akka.system.actorOf(Props[FoobarActor]) with in order to override the instantiation of actors in order to pass in the binding module?
object Foobar {
val actor = /* what goes here? */
}
As Roland mentioned, this should be as simple as just instantiating the actor with a constructor argument. I wasn't sure the implicit would work with Akka's way of doing actor instantiation with constructor args but it seems to work okay. The code should look something like this:
class FoobarActor(implicit val bindingModule: BindingModule) extends Actor
with Injectable {
val bazProvider = inject[BazProvider]
val quuxProvider = inject[QuuxProvider]
def receive = {
// do stuff here
}
}
object FoobarActor {
def apply(implicit bindingModule:BindingModule) = {
Akka.system.actorOf(Props(classOf[FoobarActor], bindingModule))
}
}
Then, if you wanted to instantiate the FoobarActor, as long as you had an implicit BindingModule in scope, you could just do:
val ref = FoobarActor()