I have a class foo which extends actor
class foo extends Actor{
def receive:PartialFunction[Any, Unit] = ???
protected def fooFunctionIWant = { print("hello")}
}
And I have another class "bar" which I want to extend foo so it will inherit the fooFunctionIWant
But when I try:
object bar extends foo {
def barFunc = {
fooFunctionIWant
}
}
and then:
bar.barFunc
I get :
Caused by: akka.actor.ActorInitializationException: You cannot create an instance of [...] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
at akka.actor.ActorInitializationException$.apply(Actor.scala:173) ~[akka-actor_2.11-2.4.1.jar:na]
at akka.actor.Actor$class.$init$(Actor.scala:436) ~[akka-actor_2.11-2.4.1.jar:na]
The only correct way to create an actor instance is by using one of the actorOf methods. Using new Actor or object Actor will fail during runtime.
You can't call any methods within the actor directly, you can only send messages to it and receive messages from it. Otherwise, if that would be possible it would break Actor encapsulation.
If you want to share code between an actor and a regular class you can put that shared code in a trait and inherit from it. However, your actor will be able to use that code internally only and will not expose any methods, its instance type returned from actorOf will still be Actor only.
Related
The akka documentation is clearly stated that it is dangerous to create an actor within an actor like this:
class ActorA extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA))
}}
I understand that the Actor's apply method is accepting this reference of the creating actor. yet I couldn't understand (nor couldn't find any example) why this is harmful and what issues it can cause?
Let's tweak your example a little bit
class ActorA(str:String) extends Actor {
def receive = ???
}
final class ActorB extends Actor {
def receive = {
case _ =>
val act = context.actorOf(Props(new ActorA("hidden")))
}}
Most of the common use case of using actors are to handle failover and supervision, shen an actor fails and needs to be restarted, the actor system needs to know how to do that. When you use Props(Props(new ActorA)), you've hidden the parameter value of "hidden" by handling it yourself.
Rather than doing that if instead, you declare how to create instances of the actor, the actor system will know exactly what it needs to do when recreating an actor -
i.e. create an instance of ActorA with a constructor argument of "hidden".
Even with your example of Actor without param
context.actorOf(Props(new ActorA))
this way of instantiating actors within another actor is not recommended because it encourages to close over the enclosing scope, resulting in non-serializable Props and possibly race conditions (breaking the actor encapsulation).
I believe we are confusing creation and declaration. The doc says that
Declaring one actor within another is very dangerous and breaks actor encapsulation. Never pass an actor’s this reference into Props!
So the problem is declaration, not creation!
Let's look at Java's:
public class MyActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK", getSelf());
}
class MyOtherActor extends AbstractActor {
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.match(String.class, handleString())
.matchAny(x -> unhandled(x))
.build();
}
private FI.UnitApply<String> handleString() {
return message -> sender().tell("OK-Inner", getSelf());
}
}
}
Now, if MyOtherActor was a normal class, we'd be able to instantiate it only from an instance of MyActor:
MyActor actor = new MyActor();
MyActor.MyOtherActor otherActor = actor.new MyOtherActor();
Which means that the constructor for MyOtherActor depends on the instance of MyActor!
Now, if Props are supposed to contain the "factory" of the actor. They need a factory method. If our MyOtherActor is declared as we did here, then our props would look like this (ish):
MyActor actor = ??? // how did you even get a reference to the actor and not the actorRef in the first place!
Props otherActorProps = Props.create(MyActor.MyOtherActor.class, () -> actor.new MyOtherActor());
And bang, here comes the kicker! Now your otherActorProps contains a reference to actor, i.e. you have closed over mutable state! If for whatever reason actor "dies", your props will still be referencing it, causing all sort of weirdness.
There is also the issue of how you get a reference to the actor in the first place, and not it's actorRef
IMHO, that's what the documentation is referring to, and not the fact of "creating" (i.e. instantiating, spawning) an actor within another one: that's absolutely normal and it's a routine operation of akka (that's why you can do getContext().actorOf(..) as well as actorSystem.actorOf(...)
The warning is there in the documentation because it's easy to accidentally close over the creating actor's state, including its this pointer (which you should never use in actor-based code).
In my experience, I've usually seen a props method put into an actor's companion object:
object ActorA {
def props() = Props(new ActorA)
}
Doing it that way ensures the returned Props isn't closing over an actor's state.
class ActorB extends Actor {
def receive = {
case _ =>
val actorB = context.actorOf(ActorA.props)
...
}
}
It's not as big of a possibility for actors that don't take constructor parameters, but once parameters come into play you need to be careful about closing over internal state.
I have an actor to which I want inject dependency using mixin. Code:
trait ProductsAware {
def getProducts: List[Product]
}
trait MyActor extends Actor with ProductsAware {
val products = getProducts
...
}
As you can see I'm just trying to decouple MyActor from concrete instance of ProductsAware trait, and provide concrete instance in other place (when creating actor).
And this is concrete implementation of ProductsAware trait:
trait ProductsAwareFirstImpl {
override def getProducts = {List(new Product())}
}
And I want to create new MyActor and inject to MyActor this concrete implementation ProductsAwareFirstImpl:
system.actorOf(Props[MyActor])
The problem is that is not safe at compile time, i.e. anyone can forget to mix the ProductsAwareFirstImplto MyActor
You can use a different Actor Props construction technique, namely the Props(new Actor) as documented here. Just make sure you are careful and not closing over any state, e.g. putting it in a object and calling it via a method should be safe. This is described in the documentation, but a quick mockup would look like this:
object MyActor {
def newActorWithFirstImpl = new MyActor with ProductsAwareFirstImpl
}
//...
system.actorOf(Props(MyActor.newActorWithFirstImpl))
To be sure that some trait is mixed to you actor you may user explicit self type reference:
trait MyActor extends Actor {
self: ProductsAware =>
val products = getProducts
// ...
}
So no one could instantiate MyActor without mixin ProductsAware
I am wanting to test one of my akka actors, it uses slick to get the information from the database. In my actor I have this bit of code
CardStationPermissions.retrieveByStationID(stationID).foreach(card => {
I want to know how can I mock that function to change the output instead of relaying on whats in the database?
It's really difficult to mock things that are being called in a static way (in this case, a call on an object as opposed to an instance of a class). When you need to be able to mock and test things like this, I tend to agree with Mustafa's suggestion that creating a trait to represent the relevant methods to mock. A simple example would look as follows:
case class MyObject(id:Long)
trait MyDao{
def getData(input:String):List[MyObject] = ...
}
object MyDao extends MyDao
class MyActor extends Actor{
val myDao:MyDao = MyDao
def receive = {
case param:String => sender ! myDao.getData(param)
}
}
Here you can see that I have a trait to represent my dao methods (only 1 for this example) and then I mix that trait into a scala object as the default instantiation of that trait. When I setup my dao in my actor, I explicitly type it to the trait so that I can substitute a mock impl of that trait later.
So then if I wanted a simple test showing mocking, it could look something like this (via specs2):
class MyActorTest(_system:ActorSystem) extends TestKit(_system)
with Specification with Mockito with ImplicitSender{
def this() = this(ActorSystem("test"))
trait scoping extends Scope{
val mockDao = mock[MyDao]
val actor = TestActorRef(new MyActor{
override val myDao = mockDao
})
}
"A request to get data" should{
"pass the input to the dao and return the result to the sender" in new scoping{
mockDao.getData("foo") returns List(MyObject(1))
actor ! "foo"
expectMsg(List(MyObject(1)))
}
}
}
If I have following Actor (MyActor) with a companion object.
object MyActor {
}
class MyActor extends Actor{
}
Now I want to delcare a method in a companion object like following
object MyActor{
def doStuff(id:String){
(myActor ? Message1(id)).map {
}
}
where doStuff method will be called by a caller which has no knowledge of actors etc. now doStuff needs "myActor" reference in there. since object MyActor has no actor context or anything what's the way to access "myActor" actor in there?
EDIT Initialization of MyActor happens upon application startup, by a totally different Global Object, as follow.
val system = ActorSystem("MyActorSystem")
//create all first level actors here
system.actorOf(Props[MyActor], "MyActor")
It sounds like you want to treat the fact that you are using an actor as an implementation detail of whatever service the companion object exposes, but you want to centralize the creation of actors (presumably to give them a supervisor). One option would be for the companion object to look up the actor.
Another would be to have the creation of the actor hidden in the companion object. The global object that creates the actors could, rather than creating MyActor directly, call an init method on the companion object with an ActorSystem argument; MyObject could save the ActorRef for later use. You'd have to make the variable #volatile in that case.
If you really want to create your myActor elsewhere and then be able to use it in this companion, then you could try something like this:
object MyActor {
def doStuff(id:String)(implicit sys:ActorSystem) = {
(sys.actorSelection("/user/MyActor") ? Message1(id)).map {}
}
}
By making the context an input (and it doesn't have to be an implicit, could be explicit too) different pieces of code pass it in/make it available in different ways. For example, in another actor, you already have the actor system available via context.system but if you are outside of an actor, then you will probably have needed to make the actor system itself available on some sort of global object and then imported into scope.
The thing is that, even though it is defined in the companion object of MyActor, doStuff can't access the reference (ActorRef) to the instantiated actor without explicitly importing the ActorRef myActor.
I think it would be better to write the MyActor object as follows:
object MyActor {
val myActor = system.actorOf(Props[MyActor], "MyActor")
def doStuff(id:String) = {
(myActor ? Message1(id)).map {}
}
}
Import this object in your Global object so that the creation of myActor would be done as soon as the Global object is used.
I'm currently exploring using Scaldi for Dependency Injection in a Play2.2 application.
I have read the documentation on Scaldi's website, but what is unclear to me is how to use it with Akka.
What I have so far in my project:
Models/ (Daos and case classes)
User.scala
Services/ (Akka Actors)
UserService.scala
ProfileService.scala
Managers/ (Regular Manager Classes)
UserManager.scala (The Trait Interface)
UserManagerImpl.scala (An actual implementation)
UserManagerMock.scala (Mocked version)
etc..
In UserService.scala I would use an instance of the UserManager to do the work:
class UserService extends ServiceActor with Injection
{
val userManager = inject[UserManager]
def receive = {
case Register(email: String, password: String)
}
}
object UserService extends Service
{
case class Register(email: String, password: String)
override protected val actorRef = Akka.system.actorOf(Props[UserService].withRouter(SmallestMailboxRouter(resizer = Some(resizer))))
}
Then depending on the injected manager, the actor can be sort of mocked if it delegate all the work to the manager?
However, what if the managers needs to call other Services, which are just companion objects? Or Services calling other services that are also referenced via companion objects?
Does anyone have some pointers on how to integrate Akka with Scaldi?
You mentioned, that you are using companion objects as a services. I also noticed, that you are
creating actors inside of the objects. In general I will discourage you from doing this. Scala (companion) objects
are just singletons. While they can be useful and appropriate in some circumstances, in general they are considered to be
an anti-pattern rather than a pattern, especially if you want to do dependency injection or inversion of control in
your application. There are a lot of reasons for this, but the most important ones in this case are: it's hard to mock them,
it's hard to control their instantiation, and in general they represent an opposite of inversion of control.
Another problem, is that you are creating actors inside of these singleton objects. Very important aspect of actor model is
supervision hierarchy. By creating this actor
(UserService in your case) in isolation, you most probably let guardian actor to be it's supervisor, which in most case
is not what you want. So I would recommend to create most of the actors within another actors, except few,
that need to be top-level actors. This will make sure that they have proper supervision hierarchy.
These ideas also remain the same if you are using Scaldi. scaldi-akka provides
convenient way to inject an ActorRef or Props for some particular actor. Here is a small example of how you can
inject normal bindings and ActorRefs:
class ProfileManager (implicit inj: Injector) extends Injectable
trait UserManager {
def register(email: String, password: String): User
}
class UserManagerImpl(implicit inj: Injector) extends UserManager with Injectable {
val profileManager = inject [ProfileManager]
def register(email: String, password: String) = ???
}
class UserService(implicit inj: Injector) extends Actor with AkkaInjectable {
val userManager = inject [UserManager]
import UserService._
def receive = {
case Register(email, password) =>
userManager
}
}
object UserService {
case class Register(email: String, password: String)
}
class ReceptionistService(implicit inj: Injector) extends Actor with AkkaInjectable {
val userManager = injectActorRef [UserService]
def receive = ???
}
Please note, that injectActorRef creates and actor within the context of current actor. So the equivalent would
be:
val userManager = context.actorOf(injectActorProps[UserService])
Now you need to create binding for the ActorSystem (it's optional, and if you are using Play, you probably
need to get ActorSystem from the play application, which already has one), services (which are actors in your case)
and managers:
implicit val module = new Module {
bind [ActorSystem] to ActorSystem("MySystem")
binding toProvider new UserService
binding toProvider new ReceptionistService
bind [UserManager] to new UserManagerImpl
binding to new ProfileManager
}
It is important to bind Actors with toProvider. This will make sure, that each time Akka asks Scaldi for some
particular Actor, it will always get the new instance of it.
Now, if you want ReceptionistService to be your top-level actor, you can use it like this:
implicit val system = inject [ActorSystem]
val receptionist = injectActorRef [ReceptionistService]
receptionist ! DoStuff
In this case, systems guardian actor would be it's supervisor.