Instantiation in AKKA Microkernel - scala

Having followed the documentation example (2.1.4), I was having trouble with a Microkernel loaded actor processing messages, where the Bootable extension class is defined as follows:
class HelloKernel extends Bootable {
val system = ActorSystem("hellokernel")
def startup = {
system.actorOf(Props[HelloActor]) ! Start
}
def shutdown = {
system.shutdown()
}
}
If a dummy (i.e. not used anywhere else in the code) instance is created, as shown below, messages are then processed as expected.
class HelloKernel extends Bootable {
val system = ActorSystem("hellokernel")
val dummyActor = system.actorOf(Props[HelloActor])
def startup = {
system.actorOf(Props[HelloActor]) ! Start
}
def shutdown = {
system.shutdown()
}
}
Should there indeed be a dummy instantiation or, by doing it, am I causing some side effect, resulting in messages being processed?
Based on the code given by Thomas Letschert in Akka 2.1 minimal remote actor example I have turned the server side into a Microkernel hosted actor.
import akka.actor.Actor
import akka.actor.ActorLogging
import akka.actor.ActorSystem
import akka.actor.Props
import akka.kernel.Bootable
class Joe extends Actor {
def receive = {
case msg: String => println("joe received " + msg + " from " + sender)
case _ => println("Received unknown msg ")
}
}
class GreetServerKernel extends Bootable {
val system = ActorSystem("GreetingSystem")
val joe = system.actorOf(Props[Joe], name = "joe")
println(joe.path)
joe ! "local msg!"
println("Server ready")
def startup = {
}
def shutdown = {
println("PrimeWorker: Shutting Down")
system.shutdown
}
}
In this case the dummy instantiation, which when removed messages are not processed, is
val joe = system.actorOf(Props[Joe], name = "joe")
The caller code is
import akka.actor._
import akka.actor.ActorDSL._
object GreetSender extends App {
implicit val system = ActorSystem("GreetingSystem")
val joe = system.actorFor("akka://GreetingSystem#127.0.0.1:2554/user/joe")
println(joe.path)
val a = actor(new Act {
whenStarting { joe ! "Hello Joe from remote" }
})
joe ! "Hello"
println("Client has sent Hello to joe")
}

If the code you posted is indeed accurate, then just move the instantion of the joe instance into the startup operation instead of in the constructor for the bootable class:
def startup = {
system.actorOf(Props[Joe], name = "joe")
}
The actor tied to the name joe needs to have been started up before someone can look it up by name and send messages to it. It's basically the same thing as starting it up in the constructor of the bootable class, but I believe that convention dictates to do all actor instantiation in the startup function as opposed to the bootable class body (and thus the constructor)

Related

How to broadcast the same string message to all actors via ConsistentHashingPool in akka

I am new to Akka and stuck with this issue.
I have 4 actors but Somehow the broadcast message is always going to one actor
here is a sample code
def hashMapping: ConsistentHashMapping = {
case ReduceNameTitlePair(name,title) => {
//println(s"\n *** Using ${name} as the key")
name
}
}
var actorReduceRouter = context.actorOf(RemoteRouterConfig(ConsistentHashingPool(numReducers,hashMapping = hashMapping), addresses).props(Props(classOf[ReduceActor])))
actorReduceRouter ! Broadcast("SEND ME YOUR DATA"))
Please help
In Classic Actors you can use Broadcast to send a message to all actors in a router, including ConsistentHashingRouter. When I run the below code I get the message received on all three actors.
You appear to be using Broadcast above, so I'm suspicious of your remoting configuration. But since you don't really post anything about your remoting setup here there's not much I can do to troubleshoot. I'd recommend using cluster-aware routers over manual remoting, but I don't know if that is in any way related to your problem.
import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.routing.{Broadcast, ConsistentHashingPool}
import akka.routing.ConsistentHashingRouter.ConsistentHashMapping
object Worker {
def props(): Props = Props(new Worker())
}
class Worker extends Actor with ActorLogging {
def receive = {
case s: String => log.info(s"${self.path.name} : $s")
}
}
object AkkaQuickstart extends App {
val system = ActorSystem("UntypedRouter")
def hashHapping: ConsistentHashMapping = {
case s: String => s
}
val router = system.actorOf(
ConsistentHashingPool(3, hashMapping = hashHapping).props(Worker.props())
)
router ! Broadcast("hello")
}

Testing actor crash using TestActorRef

I am new to actors, I am learning, how to test actors using TestActorRef
My actor code:
package actors
import actors.GreetingActor.Hi
import akka.actor.Actor
object GreetingActor {
case class Hi()
}
class GreetingActor extends Actor {
var greeting = ""
override def receive: Receive = {
case Hi() =>
greeting = "Hi"
case _ =>
throw new IllegalArgumentException("not supported message")
}
override def postRestart(reason: Throwable) = {
println(s"actor is restarted because of ${reason.getMessage}")
}
}
I am sure that everything works as I want in this code, but I can't show it in test. Especially I can't show that one of the most important thing, that my actor crashed. The test is very simple and obvious I send message that is not Hi() and should track somehow that actor crashed with IllegalArgumentException. My current test code:
package actors
import actors.GreetingActor.Hi
import akka.actor.ActorSystem
import akka.testkit.{TestActorRef, TestKit}
import org.scalatest.{MustMatchers, WordSpecLike}
class GreetingActorTest extends TestKit(ActorSystem("testsystem")) with WordSpecLike
with MustMatchers with StopSystemAfterAll {
"A Hello Actor" must {
"change state when it receives a message, single threaded" in {
val greetingActor = TestActorRef[GreetingActor]
greetingActor ! Hi()
greetingActor.underlyingActor.greeting mustBe "Hi"
}
"throw exception when it received unknown message, single threaded" in {
val greetingActor = TestActorRef[GreetingActor]
greetingActor ! "hi"
//some code that checks that actor crashed
}
}
}
The question is how can I track in test that my actor crashed using TestActorRef? Appreciate any help.
Change your test to the following:
"throw exception when it received unknown message, single threaded" in {
assertThrows[IllegalArgumentException] {
val greetingActor = TestActorRef[GreetingActor]
greetingActor.receive("hi")
}
}
Per the actor docs, you need to use receive so the exception doesn't get swallowed:
http://doc.akka.io/docs/akka/current/scala/testing.html#The_Way_In-Between__Expecting_Exceptions

Testing Akka Typed behavior

How would I test that a given behavior sends the messages I expect?
Say, three messages of some type, one after the other...
With regular actors (untyped) there was the TestProbe from regular Akka with methods like expectedMsg:
http://doc.akka.io/api/akka/current/index.html#akka.testkit.TestProbe
With akka-typed I'm scratching my head still. There is something called EffectfulActorContext, but I've no idea how to use that.
Example
Say I am writing a simple PingPong service, that given a number n replies with Pong(n) n-times. So:
-> Ping(2)
Pong(2)
Pong(2)
-> Ping(0)
# nothing
-> Ping(1)
Pong(1)
Here is how this behavior might look:
case class Ping(i: Int, replyTo: ActorRef[Pong])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => (0 until i.max(0)).map(_=> replyTo ! Pong(i))
}
}
My Hack
Now since I can't figure out how to make this work, the "hack" that I am doing right now is making the actor always reply with a list of responses. So the behavior is:
case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => replyTo ! (0 until i.max(0)).map(_=>Pong(i)).toList
}
}
Given this hacky change, the tester is easy to write:
package com.test
import akka.typed.AskPattern._
import akka.typed.ScalaDSL._
import akka.typed.{ActorRef, ActorSystem, Behavior, Props}
import akka.util.Timeout
import com.test.PingPong.{Ping, Pong}
import org.scalatest.{FlatSpec, Matchers}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
object PingPongTester {
/* Expect that the given messages arrived in order */
def expectMsgs(i: Int, msgs: List[Pong]) = {
implicit val timeout: Timeout = 5 seconds
val pingPongBe: ActorSystem[Ping] = ActorSystem("pingPongTester", Props(PingPong.pingPong))
val futures: Future[List[Pong]] = pingPongBe ? (Ping(i, _))
for {
pongs <- futures
done <- {
for ((actual, expected) <- pongs.zip(msgs)) {
assert(actual == expected, s"Expected $expected, but received $actual")
}
assert(pongs.size == msgs.size, s"Expected ${msgs.size} messages, but received ${pongs.size}")
pingPongBe.terminate
}
} Await.ready(pingPongBe.whenTerminated, 5 seconds)
}
}
object PingPong {
case class Ping(i: Int, replyTo: ActorRef[List[Pong]])
case class Pong(i: Int)
val pingPong: Behavior[Ping] = {
Static {
case Ping(i, replyTo) => replyTo ! (0 until i.max(0)).map(_=>Pong(i)).toList
}
}
}
class MainSpec extends FlatSpec with Matchers {
"PingPong" should "reply with empty when Pinged with zero" in {
PingPongTester.expectMsgs(0, List.empty)
}
it should "reply once when Pinged with one" in {
PingPongTester.expectMsgs(1, List(Pong(1)))
}
it should "reply with empty when Pinged with negative" in {
PingPongTester.expectMsgs(-1, List.empty)
}
it should "reply with as many pongs as Ping requested" in {
PingPongTester.expectMsgs(5, List(Pong(5), Pong(5), Pong(5), Pong(5), Pong(5)))
}
}
I'm using EffectfulActorContext for testing my Akka typed actors and here is an untested example based on your question.
Note: I'm also using the guardianactor provided in the Akka-typed test cases.
class Test extends TypedSpec{
val system = ActorSystem("actor-system", Props(guardian()))
val ctx: EffectfulActorContext[Ping] = new EffectfulActorContext[Ping]("ping", Ping.props(), system)
//This will send the command to Ping Actor
ctx.run(Ping)
//This should get you the inbox of the Pong created inside the Ping actor.
val pongInbox = ctx.getInbox("pong")
assert(pongInbox.hasMessages)
val pongMessages = pongInbox.receiveAll()
pongMessages.size should be(1) //1 or whatever number of messages you expect
}
Edit (Some more info): Cases where I need to add a replyTo ActorRef in my messages I do the following:
case class Pong(replyTo: ActorRef[Response])
val responseInbox: SyncInbox[Response] = Inbox.sync[Response]("responseInbox")
Pong(responseInbox.ref)
My initial approach to testing was to extend Behavior class
class TestQueueBehavior[Protocol] extends Behavior[Protocol] {
val messages: BlockingQueue[Protocol] = new LinkedBlockingQueue[Protocol]()
val behavior: Protocol => Unit = {
(p: Protocol) => messages.put(p)
}
def pollMessage(timeout: FiniteDuration = 3.seconds): Protocol = {
messages.poll(timeout.toMillis, TimeUnit.MILLISECONDS)
}
override def management(ctx: ActorContext[Protocol], msg: Signal): Behavior[Protocol] = msg match {
case _ ⇒ ScalaDSL.Unhandled
}
override def message(ctx: ActorContext[Protocol], msg: Protocol): Behavior[Protocol] = msg match {
case p =>
behavior(p)
Same
}
}
then I could call behavior.pollMessage(2.seconds) shouldBe somethingToCompareTo which was very similar to using TestProbe.
Although I think EffectfulActorContext is the right way to go, unfortunately couldn't figure out how to properly use it.

How to test Actors values with a factory as receiver

Let say I have an actor called TestedActor wich is able to save an Int value and send it back as follow:
class TestedActor extends Actor {
override def receive = receive(0)
def receive(number: Int): Receive = {
case new_number: Int => context.become(receive(new_number))
case ("get", ref: ActorRef) => ref ! number
}
}
In my test, I would like to be able to get this Integer and test it.
So i've been thinking about creating something like:
class ActorsSpecs extends FlatSpec with Matchers {
case class TestingPositive(testedActor: ActorRef) extends Actor {
override def receive = {
case number: Int => checkNumber(number)
case "get" => testedActor ! ("get", self)
}
def checkNumber(number: Int) = {
number should be > 0
}
}
implicit val system = ActorSystem("akka-stream")
implicit val flowMaterializer = ActorMaterializer()
val testedActor = system.actorOf(Props[TestedActor], name = "testedActor")
val testingActor = system.actorOf(Props(new TestingPositive(testedActor)), name = "testingActor")
testingActor ! "get"
}
This way, i'm able to create this TestingPositive actor, to get the number in the TestedActor and test it in checkNumber.
It seems to be working well, my problem is :
When the test fail, it raise an exception in the actor thread, I can see what went wrong in the console, but it is still saying that all my tests succeeded. Because (I think) the main thread is not aware of this failure.
Does someone knows an easier way than all of this TestingActor stuff?
Or any solution to tell the main thread that it failed?
Thank you
Take a look at using TestKit docs here. You can write a much simpler test for your actor. See how you like this test:
import akka.actor.{Props, ActorSystem}
import akka.testkit.{TestProbe, TestKit}
import org.scalatest.{BeforeAndAfterAll, FlatSpecLike, ShouldMatchers}
class ActorSpecs extends TestKit(ActorSystem("TestSystem"))
with FlatSpecLike
with ShouldMatchers
with BeforeAndAfterAll {
override def afterAll = {
TestKit.shutdownActorSystem(system)
}
def fixtures = new {
val caller = TestProbe()
val actorUnderTest = system.actorOf(Props[TestedActor], name = "testedActor")
}
"The TestedActor" should "pass a good test" in {
val f = fixtures; import f._
caller.send(actorUnderTest, 42)
caller.send(actorUnderTest, ("get", caller.ref))
caller.expectMsg(42)
}
"The TestedActor" should "fail a bad test" in {
val f = fixtures; import f._
caller.send(actorUnderTest, 42)
caller.send(actorUnderTest, ("get", caller.ref))
caller.expectMsg("this won't work")
}
}
Also, you should know about sender. While your get certainly works, a cleaner approach might be to reply to the sending actor:
def receive(number: Int): Receive = {
case new_number: Int => context.become(receive(new_number))
case "get" => sender ! number
}
And the test becomes:
"The TestedActor" should "pass a good test" in {
val f = fixtures; import f._
caller.send(actorUnderTest, 42)
caller.send(actorUnderTest, "get")
caller.expectMsg(42)
}
And finally, I'll shamelessly plug my recent blog post about maintaining an akka code base with my team. I feel morally obligated to give a new hAkker an opportunity to read it. :)

Error with DeadLetters and ActorRef

I encounter an error while running my project I cannot solve.
Here is my code:
import akka.actor._
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.ScalaActorRef
import akka.pattern.gracefulStop
import akka.util._
import java.util.Calendar
import java.util.concurrent._
import java.text.SimpleDateFormat
import scala.Array._
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
sealed trait Message
case class ReturnInfluenceMessage(source: ActorRef) extends Message
case class SetInfluences(source: ActorRef) extends Message
case class GetInfluence() extends Message
class Listener extends Actor {
def receive = {
case ReturnInfluenceMessage(s0urce) => println ("Listener: received influence (" + s0urce + ")")
}
}
class Entity extends Actor {
val Influences = context.actorOf(Props[Influences], name = "Influences")
def receive = {
case SetInfluences(s0urce) => context.children foreach (_.forward(SetInfluences(s0urce)))
case GetInfluence => context.children foreach (_.forward(GetInfluence))
case ReturnInfluenceMessage(source) =>
source ! ReturnInfluenceMessage(source)
}
}
class Influences extends Actor {
private var source: ActorRef = _
def receive = {
case SetInfluences(s0urce) =>
source = s0urce
println ("Influences: received " + s0urce)
println ("Influences: Influence set to " + source)
case GetInfluence =>
println ("Influences: influence sent to " + source)
sender ! ReturnInfluenceMessage(source)
}
}
object main extends App {
val system = akka.actor.ActorSystem("mySystem")
val Abel = system.actorOf(Props[Listener], name = "Listener")
val Cain = system.actorOf(Props[Entity], name = "Entity")
system.scheduler.scheduleOnce(1500 milliseconds, Cain, SetInfluences(Abel))
system.scheduler.scheduleOnce(3000 milliseconds, Cain, GetInfluence)
}
Here the error:
[INFO] [08/29/2014 15:39:08.330] [mySystem-akka.actor.default-dispatcher-2] [akka://mySystem
/deadLetters] Message [ReturnInfluenceMessage] from Actor[akka://mySystem/user/Entity
/Shadow/Influences#1407138271] to Actor[akka://mySystem/deadLetters] was not
delivered. [1] dead letters encountered. This logging can be turned off or adjusted
with configuration settings
'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
I am trying to set the variable source of the Cain actor to have this last one send the ActorRef of Abel to which a message figuring the source variable and display it.
The error happens here:
source ! ReturnInfluenceMessage(source)
, and I do not know why it occurs.
#Martynas is correct in that your sender ref will be the DeadLetter ref when your code is setup the way it is. The main issue is that you send in a message from outside of the actor system (via the scheduler) and then when you use forward, you continue to propagate the fact that you don't have a sender down into the next actor. You can remedy this by using a tell (!) instead of forward. I have modified your code sample to show this (as well as some other changes described after the code sample):
import akka.actor._
import concurrent.duration._
sealed trait Message
case class ReturnInfluenceMessage(source: ActorRef) extends Message
case class SetInfluences(source: ActorRef) extends Message
case object GetInfluence extends Message
class Listener extends Actor {
def receive = {
case ReturnInfluenceMessage(s0urce) => println(s"Listener: received influence ($s0urce)")
}
}
class Entity extends Actor {
val influences = context.actorOf(Props[Influences], name = "Influences")
def receive = {
case si # SetInfluences(s0urce) =>
influences ! si
case GetInfluence =>
influences ! GetInfluence
case rim # ReturnInfluenceMessage(source) =>
source ! rim
}
}
class Influences extends Actor {
def receive = setInfluence
def setInfluence:Receive = {
case SetInfluences(s0urce) =>
println (s"Influences: received $s0urce")
println (s"Influences: Influence set to $s0urce")
context.become(withSource(s0urce) orElse setInfluence)
}
def withSource(source:ActorRef):Receive = {
case GetInfluence =>
println (s"Influences: influence sent to $source")
sender ! ReturnInfluenceMessage(source)
}
}
object Main extends App {
val system = akka.actor.ActorSystem("mySystem")
val abel = system.actorOf(Props[Listener], name = "Listener")
val cain = system.actorOf(Props[Entity], name = "Entity")
import system.dispatcher
system.scheduler.scheduleOnce(1500 milliseconds, cain, SetInfluences(abel))
system.scheduler.scheduleOnce(3000 milliseconds, cain, GetInfluence)
}
When I ran this I did not get any deadletters. Other changes include:
Formatting (2 spaces for indents, correct casing for var/vals)
Changed GetInfluence into a case object as it did not have any fields
Used variable binding in the case statements to capture a ref to the message (via the # symbol) when we needed to send that message along
Used a two state setup for the Influences actor where it is first waiting for the state to be set (the source ref) and then switches to a state where it is able to respond properly to a GetInfluences message. Probably want to explicitly handle a GetInfluences message when in the initial state as for now it's just an unhandled message.
Got rid of the use of children.foreach as you already had a ref to the only child of that actor, so it seemed unnecessary to use this construct. I would use that construct if you had a variable amount of children to send to and in this example you don't.
When you schedule a message with
system.scheduler.scheduleOnce(...)
a sender of that message is DeadLetters which is what you are trying to send message to in
sender ! ReturnInfluenceMessage(source)
and it is also what error message says.