I have a tiny Rep server that I'm able to successfully send a message to using the below code:
import akka.actor.Actor
import akka.zeromq._
import org.zeromq.ZMQ
import akka.util.ByteString
class Sender extends Actor {
override def preStart(): Unit = {
val context = ZMQ.context(1)
val socket = context.socket(ZMQ.REQ)
socket.connect ("tcp://127.0.0.1:1234")
socket.send("test".getBytes(), 0)
println("Sent!")
//val reqSocket = ZeroMQExtension(context.system).newReqSocket(
// Array(Connect("tcp://127.0.0.1:1234")))
//reqSocket ! ZMQMessage(ByteString("test"))
}
def receive : Receive = {
case _ =>
}
}
However, if I use the commented out part instead (and comment out everything else in the def), then the server is unable to detect any message. Am I supposed to use some other sort of procedure to send the message when using ZeroMQExtension? I'm using ZeroMQ version 2.2.0.
For reference, here is the server code:
import akka.actor._
import akka.zeromq._
class ReplyActor extends Actor {
def receive = {
case _ =>
println("Received something!")
}
}
object Replyer extends App {
val system = ActorSystem("zmq")
val serverSocket = ZeroMQExtension(system).newRepSocket(
Array(Bind("tcp://127.0.0.1:1234"),
Listener(system.actorOf(Props[ReplyActor]))))
}
In your server, switch the case _ => code to the following:
case x => println("msg is: " + x)
You will then find that your ReplyActor and your Sender end up getting a 'Connecting' message. I have found that you can't send/receive anything until you get this 'Connecting' message. It just means that you are actually connected. Once you get that, then you can start sending / receiving messages.
Related
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")
}
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.
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.
I want to create a server/client system using akka remoting. At first I create a simple remote Server. (I wrote the code below for testing purposes and to clarify my concepts so it really doesn't do much.)
I want my client to send a username and a password to the server which the server can verify and reply back. At first I create a client actor. From my client object I send this actor the username and password (I use future here). The client actor then uses another future to send this username and password to the server.
The server in my code gets the username and password and prints it out. The problem is I dont get anything back from the server. Since I used a future to send the information to the server, it should reply back with a result. This is where I think I have a conceptual problem. Going through the akka documentation did not clarify this. But I an sure I am messing up something very basic. The server code is:
EDITED after suggestions from TrustNoOne and cmbaxter.
package server
import collection.mutable
import akka.actor._
import com.typesafe.config.ConfigFactory
import shared._
import shared.CaseClass._
object Server extends App {
val system = ActorSystem("ServerSystem",
ConfigFactory.parseString("""
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
netty.tcp {
hostname = 127.0.0.1
port = 5555
}
}
}
"""))
system.actorOf(Props[ServerActorClass], "ServerActor")
}
class ServerActorClass extends Actor {
def receive = {
case userPass: UserPass => {
sender ! verified()
println(userPass)
}
case testMsg: String => println("Got a msg"+ testMsg)
}
}
The client code is:
package client
import ...
object Client extends App {
val system = ActorSystem("ClientSystem",
ConfigFactory.parseString("""
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
}
remote {
netty.tcp {
hostname = 127.0.0.1
port = 0
}
}
}
"""))
val clientActor = system.actorOf(Props[ClientActor], name = "ClientActor") //the local actor
implicit val timout = Timeout(50 seconds)
val f = ask(clientActor, UserPass("a","b"))
f.onSuccess {
case GO => println("Got something back from Client actor") //Still doesn't happen!
}
}
class ClientActor extends Actor {
// create the remote actor
val server = context.actorFor("akka.tcp://ServerSystem#127.0.0.1:5555/user/ServerActor")
implicit val timout = Timeout(1 seconds)
def receive = {
case a: String => println("back" + a)
case a: UserPass => {
val f: Future[Any] = (server ? a)
f.onSuccess {
case response: verified => {
println("Got something back from server") //Does happen now!
val asker = sender()
asker ! GO()
}
case response: verificationFailed => {
val asker = sender()
asker ! NO()
}
}
}
}
}
Case classes that are shared by both the client and the server:
package shared
case object CaseClass {
case class verified //Server msg to acknowledge user and pass successful verification
case class verificationFailed //Server msg saying user pass verification failed
case class GO
case class NO
case class UserPass(user:String, pass:String)
I want to know what I am doing wrong. If someone could explain rather than just point out the problem, it would be great, since I am looking to learn.
In the server actor, you're sending the response like this:
sender ! CaseClass.verified
You are actually sending the "verified" class companion object back to the client. You should either make the verified class a case object or send back to the client a verified instance:
sender ! CaseClass.verified()
You are doing other (unrelated) errors:
closing over sender in the future callback (make a local alias val replyTo = sender())
not respecting naming conventions (capital letters, etc)
using deprecated "actorFor". you have to use actorSelection (see akka docs)
You're exiting without waiting for a response.
implicit val timout = Timeout(50 seconds)
val f: Future[Any] = clientActor ? UserPass("s","a")
f.onSuccess {
case GO => println("Got something back from Client actor") //Doesnt happen!
}
That sets up a handler for a callback, but then your program just exists.
Minimally, you could scala.concurrent.Await.result(f)
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)