I created an FSM with Akka. However, my FSM doesn't only get messages passed that are relevant for its FSM state. Its children may also pass ActorRefs up to it, which my FSM should then pass further up to its parent. Since FSMs in Akka are (naturally) also actors, I would like to override receive to catch those ActorRefs. However, doing that broke the FSM functionality of the actor. What's the proper way to handle a situation like this?
Messages that are not relevant for any FSM state can be handled in whenUnhandled:
whenUnhandled {
case Event(someActorRef: ActorRef, _) =>
context.parent ! someActorRef
stay()
}
Though, overriding receive should, afaik, work, too.
Related
I've tried to make my actor class observable (extends Actor with Observable[T]). However, there is an error message that I have to implement the asJavaObserver value but there is no asJavaObserver in observable trait.
Aren't you mixing two separate programming paradigms? Actors only communicate by messages. So if anyone is interested in the state change of an actor it must receive a message from the actor.
The observable stuff is for other OO programs which don't use Actor model.
I'm doing something like this:
...lots of surrounding context...
val actor = context.actorOf(Props(new Actor(...))
(actor ? message) onComplete {
case Done => {
println("done")
Do stuff with the surrounding context of this actor
}
case _ => {
println("got wildcard") // try to handle error message here
}
}
Actor is failing at initialization with
akka.actor.ActorInitializationException (in that actors context)
In the parent actor I am getting **dead letters encountered.**
since actor was never created properly and "message" couldn't be delivered.
In this scenario the "ask?" pattern never returns properly.
I could create a SupervisorStrategy in the parent global level, but I need to understand the context of the actor that generated the exception and it isn't possible (or convenient) handling it at the global level
Is there a way to "catch" the initialization exception in the "ask" context actor ? message?
According to akka philosophy ask should be used only when you interact with the actor from the outside of the actor system.
Since you have a reference to the context seems that you are inside the actor code. So you should try to get rid of ask.
If I'm wrong and you call ask from non-akka code then you shouldn't try to rely on anything that happens inside the actor system. All that you have is an ActorRef with no guaranties what is on the other side of this reference.
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.
My actor that is described with an FSM is waiting for a trigger (in Idle state). When it gets it it starts processing some data (and goes to Running state) and when it is done it goes back to Idle state.
If I understand the FSM model correctly, from this point of view there were two events:
processing started (Idle->Running) and processing completed (Running->Idle).
But from the actor point of view there was only one message.
One possibility is to delegate the processing itself to another actor. So I can forward the triggering event and go to Running state, then when got the result I go to Idle.
It has the advantage that the FSM itself can quickly react to requests (e.g. asking what's the current state), but it makes the design more complicated.
Another one is to send a completed message to self when the actor has completed processing, which will trigger the Running -> Idle transition, but it looks a bit strange for me.
What other options do I have?
Note: there are several other states with various transitions so I'd like to stick to the FSM model.
Since it seems like you have an actor that needs to do processing and make transitions to an FSM, I suggest you follow these guidelines (some basic code outline follows this list):
Actor A receives the message in question that will trigger some processing
Actor A transitions a separate FSM actor, say F, (akka.actor.FSM) to the appropriate state. Actor A on startup would spawn the specific FSM to track the state for the corresponding context (e.g. for all transactions or state per transaction or some other context). The code outline below uses all processing or completed transactions as the context for the example but may need to be changed.
Actor A then triggers whatever processing should be triggered for the message. Remember actors shouldn't block generally, but here is an answer that provides more guidelines on when an Akka actor may block.
Alternative: If you can trigger long running processing without blocking and ensure you receive the necessary events after processing stages by the other party, then you could eliminate the front Actor A and just have the FSM actor F. You should look at onTransition in this case.
So my code outline suggestion is based on what I understood from the question is:
/* Events */
sealed trait MyEvents
case class ProcessingStarted(txnId: Long) extends MyEvents
case class ProcessingFinished(txnId: Long, result: Result) extends MyEvents
/* Valid states for your FSM */
sealed trait MyStates
case object Idle extends MyStates
/* Constructor arguments could be anything, I randomly chose a Long for a transaction ID which may be specific to a job */
case object Processing extends MyStates
/* define more case classes or objects depending on the rest of the states */
/* Valid internal state data types for FSM */
sealed trait MyDataTypes
case object Uninitialized extends MyDataTypes
case class StateData(processingIds: Seq[Long], resultMap: Map[Long, Result]) extends MyDataTypes
import akka.actor.{ Actor, ActorRef, FSM }
import scala.concurrent.duration._
class ActorF extends FSM[MyStates, MyDataTypes] {
startWith(Idle, Uninitialized)
when(Idle) {
case Event(ProcessingStarted(txnId), Uninitialized) =>
goto(Processing) using StateData(Seq(txnId), Map.empty[Long, Result])
case Event(ProcessingStarted(txnId), StateData(emptyIds, resultMap)) =>
goto(Processing) using StateData(Seq(txnId), resultMap)
}
when(Processing) {
case Event(ProcessingFinished(txnId, result), StateData(processingIds, resultMap)) => {
val remainingIds = processingIds diff Seq(txnId)
val newResultMap = resultMap + (txnId -> result)
if (remainingIds.isEmpty) {
goto(Idle) using StateData(remainingIds, newResultMap)
} else {
stay using StateData(remainingIds, newResultMap)
}
}
}
initialize()
}
// inside Actor A do something like this for creating the FSM actor (just like other actors)
val f = system.actorOf(Props(classOf[ActorF], this))
// send an event message to it just like other types of actors
f ! ProcessingStarted(txnId)
If you choose to trigger off non-blocking processing requests to other parts of your code you can use onTransition to add the trigger code in as necessary. You may also want to update the MyEvents case classes to a different tense. The event naming was used above was to show that something else was responsible for triggering that off (e.g. Actor A the received the initial message to do some things).
Also take note of Supervision capabilities of Akka which could be used here to supervise the actors in question.
For more details read the following which might help further with building your FSM, testing it, using non-blocking methods to trigger long-running processing externally. All of which might be useful for your needs:
Scala docs for Akka 2.2.x: FSMs
Scala docs for Akka 2.2.x: Testing
Scala docs for Akka 2.2.x: Akka IO for non-blocking
Scala docs for Akka 2.2.x: ZeroMQ
I want to have the possibility to put actors to sleep for a while. The actors should decide themselves how long they are going to sleep. As Thread.sleep() is not a recommended way of doing this I thought of using the scheduler in akka. I therefore defined an actor were another actor can register for being woken up.
class Scheduler extends Actor {
def receive = {
case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
sender ! Ring
}
}
}
But the sending actor never receives the Ring message.
So my questions are
Is scheduling with the scheduler recommended inside an actor?
Why is the sending actor never receiving the Ring message?
If this is not possible what is the recommended way of solving the problem?
Let me first answer the title question: yes, it is possible to use the scheduler inside an actor.
case Sleep(duration) =>
context.system.scheduler.scheduleOnce(duration, self, Ring)
Now to the question behind the question
You did not say what you actually want to achieve, so I’m making an educated guess here that you want the actor—which normally does something called “X”—to do something called “Y” for a while, suspending the “X” activity. The full solutions to this would be
class Sleepy extends Actor {
def receive = {
... // cases doing “X”
case Sleep(duration) =>
case object WakeUp
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
context.become({
case WakeUp => context.unbecome()
// drop the rest
}, discardOld = false)
}
}
The same could as well be implemented using the FSM trait and switching between the normal and the sleeping state. And of course you can do whatever you want while sleeping, e.g. mix in the Stash trait in Akka 2.1 and call stash() for all (or some) messages while sleeping, unstashAll() when getting the WakeUp message; or you could do something else altogether. Actors are very flexible.
What actors don’t do
Actors never really sleep, they always handle incoming messages. As shown above, you can define what that means, but the basic principle is that you cannot suspend an actor such that it will not process the messages in its mailbox.
You are closing over "sender" in your closure that's passed to the scheduler. This means that the Ring message is most likely being sent to the wrong actor. You should do this instead:
case Sleep(duration) =>
val s = sender
context.system.scheduler.scheduleOnce(duration) {
s ! Ring
}
}
Roland Kuhn's answer covers the subject, I just wanted to add that there's another common use-case for using the scheduler:
when sending a message to a different actor and waiting for this actor to respond, it's quite common to cap the wait with a timeout.
otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self