Let's say I have a very simple actor class which receives any message and prints to the console.
class SimpleActor extends Actor{
def receive: Receive = {
case message =>
println(s"[${this}][${self}] received message: ${message}")
}
}
val simpleActor = actorSystem.actorOf(Props[SimpleActor], "simpleActor")
simpleActor ! "Hey"
As you can see I am using both this and self here and both has different values. Its output is something like:
[pkg.ActorRunner$SimpleActor#65cca69][Actor[akka://ActorDemo/user/simpleActor#934141660]] received message: Hey
I want to understand the difference between self and this because in complex scenarios(production system) if the actor breaks, for example: throws an exception than I think value for this gets changed.
this is classic java reference to the object extending Actor trait while self is a reference to the ActorRef that is what you need to send messages (! or tell and ? or ask)
You can't send messages to this
You shouldn't pass reference to this outside actor while passing reference to self is perfectly fine, in fact it is sent implicitly when you send a message to an actor from another actor. If you pass this to another object you will be risking actor's state encapsulation. Remember that the only way to communicate with an actor is via messages, i.e. with its ActorRef
self will remain valid after actor restart, aka you can keep sending messages to the same ActorRef (self). Only when the actor is stopped the reference to ActorRef is no longer valid and messages sent to that address will end in Dead Letters.
this will no longer be valid after actor restart. A new object of type Actor is instantiated to clear the actor state that could be compromised due to failure.
What restarting means
Unless the failure is specifically recognizable, the third cause cannot be ruled out, which leads to the conclusion that the internal state needs to be cleared out. If the supervisor decides that its other children or itself is not affected by the corruption—e.g. because of conscious application of the error kernel pattern—it is therefore best to restart the child. This is carried out by creating a new instance of the underlying Actor class and replacing the failed instance with the fresh one inside the child’s ActorRef; the ability to do this is one of the reasons for encapsulating actors within special references. The new actor then resumes processing its mailbox, meaning that the restart is not visible outside of the actor itself with the notable exception that the message during which the failure occurred is not re-processed.
Actor Reference and Path Equality
Note that a restart of an actor caused by a failure still means that it is the same actor incarnation, i.e. a restart is not visible for the consumer of the ActorRef.
What is the Difference Between Actor Reference and Path?
An actor reference designates a single actor and the life-cycle of the reference matches that actor’s life-cycle; an actor path represents a name which may or may not be inhabited by an actor and the path itself does not have a life-cycle, it never becomes invalid. You can create an actor path without creating an actor, but you cannot create an actor reference without creating corresponding actor.
You can create an actor, terminate it, and then create a new actor with the same actor path. The newly created actor is a new incarnation of the actor. It is not the same actor. An actor reference to the old incarnation is not valid for the new incarnation. Messages sent to the old actor reference will not be delivered to the new incarnation even though they have the same path.
Related
I am designing an actor that should schedule sending a message to itself.
I notice that there are at least two ways to do it.
I would like to understand the difference to choose the right one.
The first is one method of akka.actor.Timers:
def startSingleTimer(key: Any, msg: Any, timeout: FiniteDuration): Unit
The second is the pretty common way with scheduler of actor context system:
final def scheduleOnce(
delay: FiniteDuration,
receiver: ActorRef,
message: Any)(implicit executor: ExecutionContext,
sender: ActorRef = Actor.noSender): Cancellable
Question:
Which is the main difference between them in case of scheduling a
message to itself?
Is it a good idea to pass actor context to scheduleOnce method?
akka.actor.Timers.startSingleTimer
Can be used only within an actor
Allows only scheduling a message to self, ie not possible to schedule a message to some other actors
If actor dies, the active timers are cancelled automatically
Keeps track of active timers by user provided key
context.system.scheduler.scheduleOnce
Can be used to schedule messages outside and inside actors
Requires explicit ActorRef for receiver and optional sender
There is no automatic clean-up process. All should be handled explicitly by calling returned akka.actor.Cancellable
So, if you just need to schedule messages to itself, pick akka.actor.Timers
Is it a good idea to pass actor context to scheduleOnce method?
Not sure in what way you want to do it, but in general actor context must be used only within receive method and not passed outside of an actor neither used in callback methods of Futures.
In my application, I have a class which needs to communicate with an existing actor already created in an actorSystem. How do I get a reference to that actor from this non-actor class?
If you have the reference to the actor system (https://doc.akka.io/api/akka/current/akka/actor/ActorSystem.html), then you can simply invoke actorSelection with the path of the actor. This will give you an ActorSelection, on which you can call resolveOne, and then wait until you get the reference of the actor. Once you have the actor reference, you can send messages to it.
Here is more information about addressing actors: https://doc.akka.io/docs/akka/current/general/addressing.html .
If I create an logging actor like so
val logger: ActorRef =
actorSystem.actorOf(Props(new Logger()))
and the logger restarts due to an Exception, my logger stops writing to disk.
I had been sending messages logger ! msg
Am I correct in assuming that the ActorRef did not update when the supervisor restarted my logging actor?
ActorRef should be properly updated by Akka to point to the new instance of an actor. The docs clearly state that:
A reference pointing to a terminated actor does not compare equal to
a reference pointing to another (re-created) actor with the same path.
Note that a restart of an actor caused by a failure still means that
it is the same actor incarnation, i.e. a restart is not visible for
the consumer of the ActorRef.
Also here:
When actorOf() is called it assigns an incarnation of the actor
described by the passed Props to the given path. An actor incarnation
is identified by the path and a UID. A restart only swaps the Actor
instance defined by the Props but the incarnation and hence the UID
remains the same.
The lifecycle of an incarnation ends when the actor is stopped. At
that point the appropriate lifecycle events are called and watching
actors are notified of the termination. After the incarnation is
stopped, the path can be reused again by creating an actor with
actorOf(). In this case the name of the new incarnation will be the
same as the previous one but the UIDs will differ. ...
An ActorRef always represents an incarnation (path and UID) not
just a given path. Therefore if an actor is stopped and a new one with
the same name is created an ActorRef of the old incarnation will not
point to the new one.
That's one of the main advantages of using ActorRefs, otherwise it would be much more inconvenient to work with actors.
You need to check your supervisor strategy and make sure that the actor is actually restarted.
Default strategy is:
final val defaultStrategy: SupervisorStrategy = {
def defaultDecider: Decider = {
case _: ActorInitializationException ⇒ Stop
case _: ActorKilledException ⇒ Stop
case _: Exception ⇒ Restart
}
OneForOneStrategy()(defaultDecider)
}
Thus if you get an Exception your actor will be restarted and ActorRef should be valid, but if you get other types of Throwable then it will be stopped and ActorRef will become invalid.
I have got long running processes, let's say 2h to 1day. Each process starts its lifecycle with an update message and then continues to listen further concurrent updates. In the update message there is a unique target identifier.
If I want to represent each process with an Actor, how do I initialize the actor? I clearly need to do an atomic look-up/create operation based on the value of the identifier in the update message? How to do I design this with scala/akka?
Setup a single actor that performs the management of these process actors (say a ProcessManager actor). This actor will support requests to get a process actor for a particular process id. Internally, it will see if that child already exists or not. If it exists, it will respond to the sender with that ref. If not, it will create it and then respond to the sender with that ref. Because this manager actor processes it's mailbox serially (as all actors do), you don't have to worry about race conditions with the lookup/create. A very simplified example of this:
case class GetProcessHandler(processId:Int)
class ProcessManager extends Actor{
def receive = {
case GetProcessHandler(id) =>
val name = s"proc_$id"
val handler = context.child(name).getOrElse(
context.actorOf(Props[ProcessHandler], name)
)
sender ! handler
}
}
class ProcessHandler extends Actor{
def receive = {
...
}
}
You can specify your starting actors in your application.conf. And then your main program you can create/initialize these actors by using your ActorSystem.
I'm using akka to create a supervisor :
mySupervisor = actorSys.actorOf(Props.create(MyActor.class, MyProperties()));
class MyProperties(){
String param1;
String param2;
//param1 & param2 are set in a configuration file
}
Since creating a supervisor from the ActorSystem is expensive I'm just doing this once. I'm using the class MyProperties in order to
access various parameters that are required within the actor. I do not want to add the logic for setting the propertes to the actor itself so the actor
has little work to perform as possible and the usually these peoperties will not change. But when the properties do change how can I update
the child actors of the supervisor ? I do not think I can change the state of mySupervisor (since immutable) so does this mean I will need to create a new supervisor with the
new properties configuration ?
You should never never ever ever ever ever change the state of an actor with anything except a message sent to that actor.
If you need to change the properties of a child actor, you can:
Kill the actor and create a replacement with the new properties
Send a message to the actor with new properties
In addition, messages sent to an actor should be immutable (final String param1). If you need to access an actor's internal state, you should send that actor a message asking for it and then have the actor reply to that request with whatever (immutable) state is needed.