I'm trying to send a single message to several actors. Investigation led me to the code below, but it doesn't work. The message that's "wrapped" in the Broadcast object disappears, and the plain string ends up in the dead letter box.
Can someone tell me what I'm missing? (Edit: I've added the correction below)
import akka.actor.{Actor, ActorSystem, Props}
import akka.routing.{Broadcast, BroadcastRoutingLogic, Router}
object RouterAndBroadcast {
class MyRoutee extends Actor {
override def receive: Receive = {
case x => println(s"MyRoutee $this got message $x")
}
}
def main(args: Array[String]): Unit = {
val system = ActorSystem.create("system")
val mr0 = system.actorOf(Props[MyRoutee])
val mr1 = system.actorOf(Props[MyRoutee])
val mr2 = system.actorOf(Props[MyRoutee])
/* This was the error:
val router = new Router(BroadcastRoutingLogic())
router.addRoutee(mr1)
router.addRoutee(mr2) */
// This is the corrected version:
val router = new Router(BroadcastRoutingLogic())
.addRoutee(mr1)
.addRoutee(mr2)
mr1 ! "Hello number one!"
mr2 ! "Ahoy two, me old mate!"
router.route(new Broadcast("Listen up!"), mr0) // vanishes??
router.route("Listen up!", mr0) // ends up in dead letters
mr1 ! "Number one, are you still there?"
mr2 ! "Two, where's the grog?"
router.route(new Broadcast("Still shouting!"), mr0) // also vanishes
Thread.sleep(5000)
system.terminate()
}
}
Router.addRoutee returns a copy with the routee added, it doesn't modify ther Router in place, see:
https://github.com/akka/akka/blob/b94e064a34a7f6a9d1fea55317d5676731ac0778/akka-actor/src/main/scala/akka/routing/Router.scala#L140
/**
* Create a new instance with one more routee and the same [[RoutingLogic]].
*/
def addRoutee(routee: Routee): Router = copy(routees = routees :+ routee)
so instead try
router = router.addRoutee(mr1).addRoutee(mr2)
Related
What is the best way to get the current value of an infinite stream which aggregates values and by definition never complete
Source.repeat(1)
.scan(0)(_+_)
.to(Sink.ignore)
I would like to query from Akka HTTP the current counter value. Should I use dynamic stream ? The broadcastHub and then from Akka http subscribe to the infinite stream on GET request ?
One solution could be to use an actor to keep the state you need. Sink.actorRef will wrap an existing actor ref in a sink, e.g.
class Keeper extends Actor {
var i: Int = 0
override def receive: Receive = {
case n: Int ⇒ i = n
case Keeper.Get ⇒ sender ! i
}
}
object Keeper {
case object Get
}
val actorRef = system.actorOf(Props(classOf[Keeper]))
val q = Source.repeat(1)
.scan(0)(_+_)
.runWith(Sink.actorRef(actorRef, PoisonPill))
val result = (actorRef ? Keeper.Get).mapTo[Int]
Note that backpressure is not preserved when using Sink.actorRef. This can be improved by using Sink.actorRefWithAck. More about this can be found in the docs.
One possibility is using Sink.actorRefWithBackpressure.
Imagina having the following Actor to store the state coming from a Stream:
object StremState {
case object Ack
sealed trait Protocol extends Product with Serializable
case object StreamInitialized extends Protocol
case object StreamCompleted extends Protocol
final case class WriteState[A](value: A) extends Protocol
final case class StreamFailure(ex: Throwable) extends Protocol
final case object GetState extends Protocol
}
class StremState[A](implicit A: ClassTag[A]) extends Actor with ActorLogging {
import StremState._
var state: Option[A] = None
def receive: Receive = {
case StreamInitialized =>
log.info("Stream initialized!")
sender() ! Ack // ack to allow the stream to proceed sending more elements
case StreamCompleted =>
log.info("Stream completed!")
case StreamFailure(ex) =>
log.error(ex, "Stream failed!")
case WriteState(A(value)) =>
log.info("Received element: {}", value)
state = Some(value)
sender() ! Ack // ack to allow the stream to proceed sending more elements
case GetState =>
log.info("Fetching state: {}", state)
sender() ! state
case other =>
log.warning("Unexpected message '{}'", other)
}
}
This actor can be then used in a Sink of a Stream as follows:
implicit val tm: Timeout = Timeout(1.second)
val stream: Source[Int, NotUsed] = Source.repeat(1).scan(0)(_+_)
val receiver = system.actorOf(Props(new StremState[Int]))
val sink = Sink.actorRefWithBackpressure(
receiver,
onInitMessage = StremState.StreamInitialized,
ackMessage = StremState.Ack,
onCompleteMessage = StremState.StreamCompleted,
onFailureMessage = (ex: Throwable) => StremState.StreamFailure(ex)
)
stream.runWith(sink)
// Ask for Stream current state to the receiver Actor
val futureState = receiver ? GetState
I want to read the messages in ShardRegions mailbox. In previous akka version, we could use the following code to get only the size of mailbox:
getContext().getMailboxSize();
Is there any way to fetch the type of messages in the mailbox?
Here is the solution
Define a wrapper mailbox for shard region like this:
class UnboundedMailboxWrapper extends MailboxType with ProducesMessageQueue[UnboundedMailboxWrapper.MessageQueue] {
def this(settings: ActorSystem.Settings, config: Config) = this()
final override def create(owner: Option[ActorRef], system: Option[ActorSystem]): MessageQueue =
new UnboundedMailboxWrapper.MessageQueue
}
object UnboundedMailboxWrapper {
class MessageQueue extends ConcurrentLinkedQueue[Envelope] with UnboundedQueueBasedMessageQueue {
val runtime = RuntimeManager.runtime
final def queue: Queue[Envelope] = this
override def enqueue(receiver: ActorRef, handle: Envelope): Unit = {
runtime.queue.add(handle)
queue add handle
}
override def dequeue(): Envelope = {
if (!runtime.queue.isEmpty) runtime.mailbox.queue.poll()
queue.poll()
}
}
}
in this mailbox we duplicate the element which added, to another queue, so when calculate size and other operation on it, there is no any impact on performance of mailbox queue
In duplicated queue we can calculate the number of messages and sort them:
def getElemets(): String = {
runtime.queue.asScala.toList.groupBy(_.message.getClass.getName)
.map(e ⇒ (e._1, e._2.length)).toSeq
.sortBy(_._2).foldLeft("") { (a, b) ⇒
b._1 + ":" + b._2 + "\n" + a
}
}
and with JMX or any other way we can call this method in runtime
and finlally assign this mailbox to ShardRegion dispatcher:
monit-dispatcher {
mailbox-type = "im.actor.server.cluster.UnboundedMailboxWrapper"
}
akka.cluster.sharding {
use-dispatcher = "monit-dispatcher"
}
After I read this excellent blog written by the AKKA team, Shutdown Patterns in AKKA 2, I run the code and it indeed works.
But when I do another experiment with a slight change, throwing out an exception in workers, then this pattern won't work. Since it's reasonable that workers may throw any kinds of exceptions during working, right?
The following are my code, two files:
Reaper.scala, copied from the article mentioned above:
import akka.actor.{Actor, ActorRef, Terminated}
import scala.collection.mutable.ArrayBuffer
object Reaper {
// Used by others to register an Actor for watching
case class WatchMe(ref: ActorRef)
}
abstract class Reaper extends Actor {
import Reaper._
// Keep track of what we're watching
val watched = ArrayBuffer.empty[ActorRef]
// Derivations need to implement this method. It's the
// hook that's called when everything's dead
def allSoulsReaped(): Unit
// Watch and check for termination
final def receive = {
case WatchMe(ref) =>
context.watch(ref)
watched += ref
case Terminated(ref) =>
watched -= ref
if (watched.isEmpty) allSoulsReaped()
}
}
TestWorker.scala
import akka.actor.{SupervisorStrategy, Props, ActorSystem, Actor}
import Reaper._
class TestReaper extends Reaper {
def allSoulsReaped(): Unit = context.system.shutdown()
override val supervisorStrategy = SupervisorStrategy.stoppingStrategy
}
// The reaper sends this message to all workers to notify them to start work
case object StartWork
class TestWorker extends Actor {
def receive = {
case StartWork =>
// do real work ...
throw new IllegalStateException("Simulate uncaught exceptions during work")
}
}
object TestWorker {
def main(args: Array[String]) : Unit = {
val system = ActorSystem("system")
val reaper = system.actorOf(Props[TestReaper])
val worker1 = system.actorOf(Props[TestWorker])
val worker2 = system.actorOf(Props[TestWorker])
reaper ! WatchMe(worker1)
reaper ! WatchMe(worker2)
Thread.sleep(3000) // make sure WatchMe will be delivered before StartWork
worker1 ! StartWork
worker2 ! StartWork
system.awaitTermination()
}
}
This program will hang forever.
It seems the reaper cannot receive Terminated messages if workers throw uncaught exceptions
Can somebody tell my why? Many thanks in advance!
Correct answer by #mattinbits:
The reason that this program hangs forever is that in my code TestWorker are not children of TestReaper even TestReaper calls context.watch(ref).
context.watch() doesn't mean becoming a child. context.watch(ref) just means that TestReaper will get notified when a TestWorker actor dies.
SupervisorStrategy and context.watch() are two different things. SupervisorStrategy will only have influence on all children actors.
Putting override val supervisorStrategy = SupervisorStrategy.stoppingStrategy in the TestReaper won't make TestWorker stopped when exceptions happen inside TestWorker. Instead we need to change the SupervisorStrategy of TestWorkers parent actor. Since all actors in the code above are created by system.actorOf(), they are children of the Guardian Actor /user, so actually we need to change the supervision strategy of the /user actor , by adding akka { actor { guardian-supervisor-strategy = "akka.actor.StoppingSupervisorStrategy" } } in application.conf
However, it's better to use another actor as the supervision actor, just like what #mattinbits does in his code.
It is not enough to watch the actors, you also have to make sure the actors stop (which is the condition under which Terminated gets sent).
By default, when an actor throws an exception, the strategy is to restart it. You need to give the actors a supervisor which will apply the Stop directive.
Have a look at the following, both tests pass (with Reaper unchanged from your version above):
import java.util.concurrent.TimeoutException
import Reaper.WatchMe
import akka.actor.SupervisorStrategy.Stop
import akka.actor._
import akka.testkit.{TestProbe, TestKit}
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike, WordSpec}
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
case object StartWork
class TestReaper extends Reaper {
def allSoulsReaped(): Unit = context.system.shutdown()
}
class TestWorker extends Actor {
def receive = {
case StartWork =>
// do real work ...
throw new IllegalStateException("Simulate uncaught exceptions during work")
}
}
class TestParent(reaper: ActorRef, probe: ActorRef) extends Actor {
def receive = {
case "Start" =>
val worker1 = context.actorOf(Props[TestWorker])
val worker2 = context.actorOf(Props[TestWorker])
reaper ! WatchMe(worker1)
reaper ! WatchMe(worker2)
worker1 ! StartWork
worker2 ! StartWork
}
override def supervisorStrategy = OneForOneStrategy() {
case ex: IllegalStateException =>
probe ! "Stopped a worker"
Stop
}
}
class TestSupervision extends TestKit(ActorSystem("Test"))
with WordSpecLike
with Matchers
with BeforeAndAfterAll{
"Supervision" should {
"Stop the actor system when the parent stops the workers" in {
val reaper = system.actorOf(Props[TestReaper])
val probe = TestProbe()
val parent = system.actorOf(Props(new TestParent(reaper, probe.ref)))
parent ! "Start"
probe.expectMsg("Stopped a worker")
probe.expectMsg("Stopped a worker")
import system.dispatcher
val terminatedF = Future {
system.awaitTermination()
}
Await.ready(terminatedF, 2 seconds)
}
}
override def afterAll(){
system.shutdown()
}
}
class TestLackSupervision extends TestKit(ActorSystem("Test2"))
with WordSpecLike
with Matchers
with BeforeAndAfterAll{
"Lack of Supervision" should {
"Not stop the actor system when the workers don't have an appropriate parent" in {
val reaper = system.actorOf(Props[TestReaper])
val worker1 = system.actorOf(Props[TestWorker])
val worker2 = system.actorOf(Props[TestWorker])
reaper ! WatchMe(worker1)
reaper ! WatchMe(worker2)
import system.dispatcher
val terminatedF = Future { system.awaitTermination()}
a [TimeoutException] should be thrownBy Await.ready(terminatedF, 2 seconds)
}
}
override def afterAll(){
system.shutdown()
}
}
By default when actors throw an exception they are restarted. Since supervision strategy is applied from parent to child, the TestParent exists to enforce the Stop directive on the children. Your original code would not work for this reason.
If you want top level actors (Those launched with system.actorOf) to stop on an exception, you could set the configuration property akka.actor.guardian-supervisor-strategy = "akka.actor.StoppingSupervisorStrategy" but in my example I prefer to use a parent actor since actor hierarchies are a normal way to organise supervision in Akka.
To run as an app, do something similar to the following:
object Main extends App {
val system = ActorSystem("Example")
val reaper = system.actorOf(Props[TestReaper])
val dummyProbe = system.actorOf(Props(new Actor{
def receive = {
case "Stopped a worker" => println("Stopped a worker")
}
}))
val parent = system.actorOf(Props(new TestParent(reaper, dummyProbe)))
parent ! "Start"
system.awaitTermination()
}
To stop the exceptions from being printed on the command line and muddying the output, change the supervision strategy as follows:
override def supervisorStrategy = OneForOneStrategy(loggingEnabled = false) {...}
I have a pretty simple actor defined as:
object CoreActor extends Actor with ActorLogging {
// val SYSTEM_NAME = "CoreActors"
val system = Akka.system()
// val system = ActorSystem.create("push", ConfigFactory.load.getConfig("push"))
val pushUri = Play.current.configuration.getString("pushservice.uri").getOrElse("akka.tcp://CentralappPush#127.0.0.1:5000")
val protocol = Play.current.configuration.getString("pushservice.protocol").getOrElse("akka.tcp")
val pushSystem = Play.current.configuration.getString("pushservice.system").getOrElse("CentralappPush")
val ip = Play.current.configuration.getString("pushservice.ip").getOrElse("127.0.0.1")
val port = Play.current.configuration.getInt("pushservice.port").getOrElse(5000)
val rootPath = Play.current.configuration.getString("pushservice.path.root").getOrElse("user")
val actorPath = Play.current.configuration.getString("pushservice.path.actor").getOrElse("PushMaster")
val selectionPath = RootActorPath(new Address(protocol, pushSystem, ip, port)) / rootPath / actorPath
val pushActor = context.actorSelection(selectionPath)
def receive = {
case pprs: List[PlaceProvider] => {
log.info("I received something")
pushActor ! pprs.map(_.clone)
context become afterSend
}
}
def afterSend: Receive = {
case pprs: List[PlaceProvider] => {
pprs.foreach(_.update) // update in the db
context.stop(self)
}
case _ => {
log.info("Did not understand message")
context.stop(self)
}
}
}
The actors are created with unique names from within a controller in the Play! framework. What I'm seeing is that when an actor is created for the first time of a place update, it does it's job and goes into the shutting down context as expected. A second call to the same action within the play framework causes this:
[ERROR] [02/18/2015 12:32:46.181] [application-akka.actor.default-dispatcher-2] [akka://application/user/OlD1vFKVLn1424259166159] null
java.lang.NullPointerException
at actors.CoreActor$$anonfun$receive$1.applyOrElse(CoreActor.scala:29)
at akka.actor.Actor$class.aroundReceive(Actor.scala:465)
at actors.CoreActor$.aroundReceive(CoreActor.scala:11)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)
at akka.actor.ActorCell.invoke(ActorCell.scala:487)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:238)
at akka.dispatch.Mailbox.run(Mailbox.scala:220)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Which is quite baffling. Why does that happen? Why does it happen only during the second time an actor of the same type is started?
You actor is an object - this enforces that there is a single instance of the actor. When an actor is stopped it will go through some processing to cleanup its resources. Since on your next request you try to re-create a new actor using the same instance the creation is failing.
Try changing it to a class.
class CoreActor extends Actor with ActorLogging {
}
As I understand it, an actor can be sent a message "fire and forget" style with the ! operator, or "Send-And-Receive-Future" style with the ? operator. An actor that is passed a message via ? must call a self.reply or the sender will receive a timeout exception. On the other hand, an actor that is passed a message via ! cannot have self.reply if the message is not being passed from another actor.
My question is, is the Actor supposed to know at compile time whether it will be invoked with ! or ? ??? Or if the necessity of self.reply can be determined at runtime, how can this be determined? Perhaps self.tryReply is involved, but the akka documentation seems to imply that a failed attempt to reply is an error case, whereas if the sender is not an actor, it is not really an error to fail to reply if the message is passed with !
Edit:
Here's some code:
package akTest
import akka.actor.Actor
object Main1 {
val worker = Actor.actorOf[ak].start()
def main(args: Array[String]) {
val resp = worker ? "Hi"
resp.get
println(resp)
}
}
class ak extends Actor {
def receive = {
case msg:String => {
val response = "Received: " + msg
println(response)
response
}
}
}
This gets
Exception in thread "main" akka.dispatch.FutureTimeoutException: Futures timed out after [4995] milliseconds
So I add a self.reply to the actor:
class ak extends Actor {
def receive = {
case msg:String => {
val response = "Received: " + msg
println(response)
self.reply(response)
response
}
}
}
This change fixes the timeout error. But now if I have a Main2 which sends a fire and forget message:
object Main2 {
val worker = Actor.actorOf[ak].start()
def main(args: Array[String]) {
val resp = worker ! "Hi"
println(resp)
}
}
, a new error is produced: [ERROR] [2/1/12 2:04 PM] [akka:event-driven:dispatcher:global-1] [LocalActorRef]
No sender in scope, can't reply.
How can I write my actor to eliminate the coupling between its manner of response and the sender's method of invoking? I don't want to have 1 version of the actor for ! and a second version of the actor for ?
if senderFuture.isDefined then you have a future to reply to