I have an actor that has a mutable state. In my receive method, I pattern match the messages and call some service that would return a Future. This Future would modify the state in my Actor instance. Is this state not thread safe? Since the Future would be executing in a different thread, is the state in my Actor this guaranteed to be thread safe?
No that will not be threadsafe as you correctly assumed. Futures run on any thread that the execution context provides.
The way to solve this is to pipe it back to the same actor. All actor's inputs must always be messages. You can find the documentation here.
Some example code:
import akka.pattern.pipe
//... inside the Actor somewhere:
val futureResult: Future[YourType] = something.thatReturnsAFuture()
futureResult.pipeTo(self)
And then amend your receive block so the result will be processed after the future completes and it is sent back to this actor:
case result: YourType => //...
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.
I have an actor that may receive messages from an external system (UDP/TCP). Based on the content of the incoming data, there are cases when I want the actor to call back to a non-aka part of my code.
In other words, I don't want to call and actor with ask and wait for some incoming data but rather be called back asynchronously.
How can I implement this without e.g. closing over the calling object (the trivial would be pass in a callback on creation of ActorRef but this would capture caller)?
Assuming you have a functional interface handleMessage - that is, a method handleMessage that only accepts immutable data - you can simply wrap it in a Future, run inside the actor's context:
import scala.concurrent.Future
// Inside your actor, this is the implicit execution context holding the thread
// pool the actor executes within. You MUST import this in order for it to be in
// the implicit scope for scala.concurrent.Future.
import context.dispatcher
Future {
handleMessage(messageData)
// If you need to know when this completes, send a message to the initiating
// actor here.
}
I am fairly new with Akka framework and Concurrency concepts. And from Akka docs, I understood that only one message in the Actor mailbox would be processed at a time. So single thread would be processing Actor's state at a time. And my doubt is that, so declaring an Actor state/data variable as mutable - 'Var'(Only when 'Val' doesn't fit), will not cause inconsistent Actor states in the case of Concurrency.
I am using Scala for development. In the following Master actor, details of workers is stored in a mutable variable 'workers'. Will it be a problem with concurrency?
class Master extends PersistentActor with ActorLogging {
...
private var workers = Map[String, WorkerState]()
...
}
I think what you are doing is fine. As you said, one of the fundamental guarantees of Akka actors is that a single actor will be handling one message at a time, so there will not be inconsistent Actor states.
Akka actors conceptually each have their own light-weight thread,
which is completely shielded from the rest of the system. This means
that instead of having to synchronize access using locks you can just
write your actor code without worrying about concurrency at all.
http://doc.akka.io/docs/akka/snapshot/general/actors.html
Also, it is a good thing that you're using a var instead of a val with a mutable map :)
Another way to consider coding situations like these is to alter the actor's "state" after each message handled. Eg.:
class Master extends PersistentActor with ActorLogging {
type MyStateType = ... // eg. Map[String, WorkerState], or an immutable case class - of course, feel free to just inline the type...
def receive = handle(initState) // eg. just inline a call to Map.empty
def handle(state: MyStateType): Actor.Receive = LoggingReceive {
case MyMessageType(data) =>
... // processing data - build new state
become(handle(newState))
case ... // any other message types to be handled, etc.
}
... // rest of class implementation
}
While it is true that there is still mutable state happening here (in this case, it is the state of the actor as a whole - it becomes effectively a "non-finite state machine"), it feels better contained/hidden (to me, at least), and the "state" (or "workers") available to the actor for any given message is treated as entirely immutable.
When is the supervisor strategy invoked ? Is it when the exception is thrown for an Actor. In below code :
#Override
public SupervisorStrategy supervisorStrategy() {
System.out.println("supervisorStrategy");
return strategy;
}
The println statement is not invoked when actor is created. Is this expected behaviour ?
Unlike the not-to-well-named receive method, which is only called during Actor initialization to acquire the PartialFunction that will handle incoming messages, the supervisorStrategy method is used when failures occur. It is a regular method that does the work of deciding how to handle a failure in a descendant Actor.
Hmm... I just noticed you're using Java, so the part about receive is presumably different for you, but the supervisorStrategy statement still applies.
I tried to implement a timer based on Scala's actors API with, the current Thread actor (Actor.self) as the timer and an anonymous Actor which does the work that needs to be completed in time.
I have the following Scala program
import scala.actors.Actor.self
import scala.actors.TIMEOUT
object Main {
def main(args: Array[String]): Unit = {
val thiz = self
actor {
// do heavy work here
thiz ! "finish"
}
self.reactWithin(1000) {
case "finish" => println("complete")
case TIMEOUT => println("timeout")
}
}
}
When I run the program, I received
Exception in thread "main" scala.actors.SuspendActorControl
scala.actors.ActorProxy#1d99a4d: caught java.lang.InterruptedException
Please show me the way to overcome the problem.
You have two types of control passing with scala-actors, thread-blocking or thread-suspension. the latter means a control exception is thrown (the thread is made available again to the thread pool manager), and the actor body re-executed when a message comes into its mailbox. See the actors tutorial for more details, esp. section "Make it Thread-less!".
The receiveWithin method uses the thread-blocking, and the reactWithin the suspension. The problem you have here is that there is no outer managing actor that catches the exception. This only works within a "proper" actor, not with the proxy created for the main thread. So if you want to wait on the main thread outside an explicit actor, you need to use thread blocking / receiveWithin:
self.receiveWithin(1000) { ... }