context().parent() in a router pool - java

I create a pool of actors like this:
public ParentActor() {
childRouter = getContext().actorOf(
new SmallestMailboxPool(actorPoolSize)
.props(Props.create(Child.class)),
"ChildRouter");
}
Then somewhere in the child actor I have the following:
if (message instanceof someMessage) {
context().parent().tell(someOtherMessage, getSelf());
}
I was expecting that the sometherMessage will be received in the ParentActor; instead, this goes into an infinite loop. To debug this further I added some logs in the child actor as follows:
log.debug("who is my parent {} ", context().parent().getPath())
This gives me the following path:
/ActorSystem/user/ParentActor/ChildRouter
Which makes me think that the parent of one of the actors in the pool is the router actor--is this the correct behavior? How should I send a message back to the actor that spawned the router actor? I am confused.

Yes, the router is the parent (or supervisor) of the routees. From the documentation:
Routees that are created by a pool router will be created as the router’s children. The router is therefore also the children’s supervisor.
When you make the following call in a routee...
context().parent().tell(someOtherMessage, getSelf());
...the someOtherMessage message is sent to the router.
The actor that you've named ParentActor is not the parent of the Child actors that are created as part of the childRouter pool. If you want a routee to send a message to ParentActor, one approach is to change the Child actor class to take an ActorRef as a constructor argument:
public class Child extends AbstractActor {
private final ActorRef target;
public Child(ActorRef target) {
this.target = target;
}
// ...
}
Then in ParentActor, when creating the router, you can pass the reference to ParentActor (with getSelf()) to the Props for creating the routees:
childRouter = getContext().actorOf(
new SmallestMailboxPool(actorPoolSize)
.props(Props.create(Child.class, getSelf())),
"ChildRouter");
Now the Child actors can send messages to ParentActor:
if (message instanceof someMessage) {
target.tell(someOtherMessage, getSelf());
}

Related

AKKA - How can I unit test my actor that handle a TCP connection?

I have an actor that binds a port a the preStart and then expect the Tcp.Bound message. Then, it will just wait for a Tcp.Connected to happen. This actor does not provides anything to its creator so I would like to receive the Tcp Message and/or mock the Tcp Manager
So far I tried to subscribe my TestKit Probe to the tcp messages. Other than that I am looking to create a class that would override the manager, but still don't know how to do it. I am using Java 8 and JUnit 5.
#Override
public void preStart() {
this.connection = Tcp.get(getContext().getSystem()).manager();
this.connection.tell(TcpMessage.bind(getSelf(), remoteAddress, 100), getSelf());
}
#Override
public AbstractActor.Receive createReceive() {
return receiveBuilder()
.match(Tcp.Bound.class, msg -> {
log.debug("Port Bound : [{}]", msg.localAddress());
this.sessionHandler = getContext().actorOf(RmiSessionHandler.props(getSelf(), settings));
this.buffer = getContext().actorOf(RmiBuffer.props(this.sessionHandler, settings));
this.connection = getSender();
}).match(Tcp.Connected.class, msg -> {
log.debug("Port Connected to : [{}])", msg.remoteAddress());
this.sessionHandler.tell(msg, getSelf());
sender().tell(TcpMessage.register(getSelf()), getSelf()); // Register ourselves
this.session = getSender();
this.isConnectedToClient = true;
You can see that my actor just creates other actors, but I don't want to go through them to test that he established the connection.
Would really like to know when my actor is sending Tcp.Bind or when a port is bound and on which port.
Here is what I've tried :
system = ActorSystem.create("sessionHandlerTest");
testProbe = new TestKit(system);
system.eventStream().subscribe(testProbe.getRef(), Tcp.Bound.class);
rmiSocket = system.actorOf(RmiSocket.props(testProbe.getRef(), settings));
Tcp.Bound bindingMessage = testProbe.expectMsgClass(Tcp.Bound.class);
Also I tried to register my probe to the tcp manager :
ActorRef tcpManager = Tcp.get(system).manager();
tcpManager.tell(TcpMessage.register(testProbe.getRef()), testProbe.getRef());
So, in short let's assume you have a class A that needs to connect to a database. Instead of letting A actually connect, you provide A with an interface that A may use to connect. For testing you implement this interface with some stuff - without connecting of course. If class B instantiates A it has to pass a "real" database connection to A. But that means B opens a database connection. That means to test B you inject the connection into B. But B is instantiated in class C and so forth.
So at which point do I have to say "here I fetch data from a database and I will not write a unit test for this piece of code"?
In other words: Somewhere in the code in some class I must call sqlDB.connect() or something similar. How do I test this class?
And is it the same with code that has to deal with a GUI or a file system?

Akka-Java Routing Issue

I have the following issue in Akka-Java.
I have one Parent Actor MainActor.class and this parent has 5 child routes. Following is the hierarchy:
My App => Main Actor => [Child Route-1,Child-Route-2,..]
Simple Use case is String input is parsed to Integer as output:
MyApp ===ask[string input]===> Main Actor ==route==> Child(parses to Integer) === integer result===> Main Actor ===result==> MyApp
Here is the Main Actor snippet:
class MainActor extends UntypedActor {
Router router; {
// ...routes are configured here
}
public void onReceive(Object message) {
if (message instanceof String) {
router.route(message, self()); // route it to child
} else if (message instanceof Integer) {
// received from child, 'tell' this result to actual sender/parent i.e, MyApp
sender().tell(message, self());
} else unhandled(message);
}
}
And Child Actor does nothing but String parsing to Integer and takes the result and sends it back to it's sender by sender().tell(result,getContext().parent())
Issue
MainActor is sending the Parsed integer result sent by child back to child itself instead of MyApp. I also tried replacing sender() to getContext().parent() in MainActor but still it did not work.
Since you receive Integers from a child actor of MainActor, the sender points to the child actor.
When you invoke tell on sender it returns the message back to the child actor.
This should work:
getContext().parent().tell(message, self())
You have 2 options:
You can either go directly from your child to your app (bypassing the root actor on the way back), by forwarding the message (see the self() -> sender() change):
if (message instanceof String) {
router.route(message, sender());
}
So when the child responds, his sender is now the app instead of the root.
Alternatively, you can use futures, the ask/pipe patten in particular
You should really go with Diego Martinola 's answer.
The reason why your code isn't working is the following:
when you use sender().tell(message, self), sender() is not MainApp, because sender() gives you the sender of the message you are currently processing. Since you are processing the Integer message from the child actor, the effect is you are sending the message back to it.
The modification you tried, i.e. getContext().parent().tell(message, self) is no good either. In this case you are sending to the parent of MainActor, not to MainApp. Actually I suspect MainApp is not even an actor, right? You can only send messages to actors. If your intention was sending back to the actor who sent the initial message to MainActor, keep in mind this is not MainApp, it is a temporary actor used by Patterns.ask. Regardless, the main point is that, in the handler of the Integer message, you have no way to get an ActorRef of that temporary actor, cause as said before, sender() gives the sender of the current message. A workaround could be getting the sender in the handler of the String message and storing it in variable for later, like this:
class MainActor extends UntypedActor {
ActorRef lastRequester;
Router router; {
// ...routes are configured here
}
public void onReceive(Object message) {
if (message instanceof String) {
lastRequester = sender();
router.route(message, self()); // route it to child
} else if (message instanceof Integer) {
lastRequester.tell(message, self());
} else unhandled(message);
}
}
But this is dangerous, since you would be relying on all Integer messages arriving before the next String message; if an Integer message for the first String message arrives after the second String message, it will be sent to the actor who send the second String. Waiting for all childs to answer is not really an option because Akka gives you at-most-once delivery semantics. You would have to create a mechanism to recognize what String message a certain Integer message is associated to and keep a list of ActorRef instead of a single one.
While the latter is not terribly complicated to implement, it is not really worth it for your use case, and I would say in most routing scenarios, Diego Martinola 's answer is the way to go.

How to determine Akka actor/supervisor hierarchy?

I am brand new to Akka (Java lib, v2.3.9). I am trying to follow the supervisor hierarchy best practices, but since this is my first Akka app, am hitting a mental barrier somewhere.
In my first ever Akka app (really a library intended for reuse across multiple apps), input from the outside world manifests itself as a Process message that is passed to an actor. Developers using my app will provide a text-based config file that, ultimately, configures which actors get sent Process instances, and which do not. In other words, say these are my actor classes:
// Groovy pseudo-code
class Process {
private final Input input
Process(Input input) {
super()
this.input = deepClone(input)
}
Input getInput() {
deepClone(this.input)
}
}
class StormTrooper extends UntypedActor {
#Override
void onReceive(Object message) {
if(message instanceof Process) {
// Process the message like a Storm Trooper would.
}
}
}
class DarthVader extends UntypedActor {
#Override
void onReceive(Object message) {
if(message instanceof Process) {
// Process the message like Darth Vader would.
}
}
}
class Emperor extends UntypedActor {
#Override
void onReceive(Object message) {
if(message instanceof Process) {
// Process the message like the Emperor would.
}
}
}
// myapp-config.json -> where the actors are configured, along with other
// app-specific configs
{
"fizzbuzz": "true",
"isYosemite": "false",
"borderColor": "red",
"processors": [
"StormTrooper",
"Emperor"
]
}
As you can see in the config file, only StormTrooper and Emperor were selected to receive Process messages. This ultimately results with zero (0) DarthVader actors being created. It is also my intention that this would result with a Set<ActorRef> being made available to the application that is populated with StormTrooper and Emperor like so:
class SomeApp {
SomeAppConfig config
static void main(String[] args) {
String configFileUrl = args[0] // Nevermind this horrible code
// Pretend here that configFileUrl is a valid path to
// myapp-config.json.
SomeApp app = new SomeApp(configFileUrl)
app.run()
}
SomeApp(String url) {
super()
config = new SomeAppConfig(url)
}
void run() {
// Since the config file only specifies StormTrooper and
// Emperor as viable processors, the set only contains instances of
// these ActorRef types.
Set<ActorRef> processors = config.loadProcessors()
ActorSystem actorSystem = config.getActorSystem()
while(true) {
Input input = scanForInput()
Process process = new Process(input)
// Notify each config-driven processor about the
// new input we've received that they need to process.
processors.each {
it.tell(process, Props.self()) // This isn't correct btw
}
}
}
}
So, as you can (hopefully) see, we have all these actors (in reality, many dozens of UntypedActor impls) that handle Process messages (which, in turn, capture Input from some source). As to which Actors are even alive/online to handle these Process messages are entirely configuration-driven. Finally, every time the app receives an Input, it is injected into a Process message, and that Process message is sent to all configured/living actors.
With this as the given backstory/setup, I am unable to identify what the "actor/supervisor hierarchy" needs to be. It seems like in my use case, all actors are truly equals, with no supervisory structure between them. StormTrooper simply receives a Process message if that type of actor was configured to exist. Same for the other actor subclasses.
Am I completely missing something here? How do I define a supervisory hierarchy (for fault tolerance purposes) if all actors are equal and the hierarchy is intrinsically "flat"/horizontal?
If you want to instantiate no more than one instance for every your actor - you may want to have SenatorPalpatine to supervise those three. If you may have let's say more than one StormTrooper - you may want to have JangoFett actor responsible for creating (and maybe killing) them, some router is also good option (it will supervise them automatically). This will also give you an ability to restart all troopers if one fails (OneForAllStrategy), ability to broadcast, hold some common statistic etc.
Example (pseudo-Scala) with routers:
//application.conf
akka.actor.deployment {
/palpatine/vader {
router = broadcast-pool
nr-of-instances = 1
}
/palpatine/troopers {
router = broadcast-pool
nr-of-instances = 10
}
}
class Palpatine extends Actor {
import context._
val troopers = actorOf(FromConfig.props(Props[Trooper],
"troopers").withSupervisorStrategy(strategy) //`strategy` is strategy for troopers
val vader = actorOf(FromConfig.props(Props[Vader]), "vader")
override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1) //stategy for Palpatine's children (routers itself)
val strategy = OneForOneStrategy(maxNrOfRetries = 100, withinTimeRange = 1) //stategy for troopers
def receive = {
case p#Process => troopers ! p; vader ! p
case t#Terminted => println(t)
}
}
That creates broadcast pools based on standard akka-config. I also shown that you can customize supervision strategies for them separately.
If you want some of actors to ignore message by some reason - just implement this logic inside actor, like:
class Vader extends Actor {
def receive {
case p#Process => ...
case Ignore => context.become(ignore) //changes message handler to `ignore`
}
def ignore = {
case x => println("Ignored message " + x)
case UnIgnore => context.become(process)//changes message handler back
}
}
This will configure ignore/unignore dynamically (otherwise it's just a simple if). You may send Ignore message to actors based on some config:
val listOfIgnorantPathes = readFromSomeConfig()
context.actorSelection(listOfIgnoredPathes) ! Ignore
You can also create broadcaster for palpatine in the same way as trooper's router (just use groups instead of pools), if you want to control heterogenous broadcast from config:
akka.actor.deployment {
... //vader, troopers configuration
/palpatine/broadcaster {
router = broadcast-group
routees.paths = ["/palpatine/vader", "/palpatine/troopers"]
}
}
class Palpatine extends Actor {
... //vader, troopers definitions
val broadcaster = actorOf(FromConfig.props(), "broadcaster")
def receive = {
case p#Process => broadcaster ! p
}
}
Just exclude vader from routees.paths to make him not receiving Process messages.
P.S. Actors are never alone - there is always Guardian Actor (see The Top-Level Supervisors), which will shut down the whole system in case of exception. So eitherway SenatorPalpatine may really become your rescue.
P.S.2 context.actorSelection("palpatine/*") actually alows you to send message to all children (as an alternative to broadcast pools and groups), so you don't need to have a set of them inside.
Based on your comment, you would still want a Master actor to duplicate and distribute Processes. Conceptually, you wouldn't have the user (or whatever is generating your input) provide the same input once per actor. They would provide the message only once, and you (or the Master actor) would then duplicate the message as necessary and send it to each of its appropriate child actors.
As discussed in dk14's answer, this approach has the added benefit of increased fault tolerance.

Akka routing with two router configs simultaneously

I have simple UntypedActor which has set of subscribers. Actor can handle 2 types of messages ('SUB' - add sender to subscribers, 'UNSUB' - remove sender from subscribers) and other messages resend to subscribers.
private static class Dispatcher extends UntypedActor {
private Set<ActorRef> subscribers;
public Dispatcher() {
subscribers = Sets.newHashSet();
}
#Override
public void onReceive(Object o) throws Exception {
if ("SUB".equals(o)) {
subscribers.add(getSender());
return;
}
if ("UNSUB".equals(o)) {
subscribers.remove(getSender());
return;
}
for (ActorRef subscriber : subscribers) {
subscriber.tell(o, getSender());
}
}
}
I want to create routers with two different strategies: broadcast, roundrobin.
final int routeeCount = 2;
BroadcastRouter broadcastRouter = new BroadcastRouter(routeeCount);
RoundRobinRouter roundRobinRouter = new RoundRobinRouter(routeeCount);
ActorRef broadCastRef = actorSystem.actorOf(Props.create(Dispatcher.class)
.withRouter(broadcastRouter), "Broadcast");
ActorRef roundRobinRef = actorSystem.actorOf(Props.create(Dispatcher.class)
.withRouter(roundRobinRouter), "RoundRobin");
Each router will create personal group of routers, but it's not suitable for me. I want to routers using same actors, because I have following use case:
Actors A and B sends message 'SUB' to broadCastRef;
broadCastRef broadcasts message to it's own 2 child actors (X1 and X2) (routeeCount = 2);
From now on I will use roundRobinRef to pass messages to actors A and B.
So the question is how to reuse actors in two different router actors?
For your use-case you do not need two different routers, since you can just send a akka.routing.Broadcast message containing your subscription request and it will be routed to all routees of the RoundRobinRouter.
In general, if you want to route to the same set of targets using two different routers, then you’ll need to create the routees separately and pass them to the routers as discussed here (scroll down a little bit).

Akka (java), non blocking broadcast to all children

Let's say I have a Region Actor, and each region has a certain number of people inside it. How do you broadcast a message to everyone, knowing that the list of people can change over time, broadcast routers seems to be the choice, but then the problem is that they have a maximum number of routees, and that I cannot dynamically append people to a router.
My question is: I know there is an EventBus, I could subscribe my people to the event Bus, but I dont want them to recieve every message posted, I want them to recieve the messages of the region.
right now in akka, we have to create a router with a certain number of routees,
example :
Router router = new router(person1, person2)
this is bad because At the beggining there is no one in the region, i don't know the people who will join my region.
is there a way to make a kind of dynamic router :
example :
Region region = new region()
region.router = new Router()
Person person1 = new Person()
region.router.subscribe(person1);
region.router.tell("hello",null);
Your solution is already very close: you need a router, but not one of the special-made pre-fabricated ones. Instead just write an actor which forwards messages to subscribers:
class MyRouter extends UntypedActor {
final Set<ActorRef> subscribers = new HashSet<ActorRef>();
#Override public void onReceive(Object msg) {
if (msg instanceof Subscribe) {
subscribers.add(getSender());
} else if (msg instanceof Unsubscribe) {
subscribers.remove(getSender());
} else {
for (ActorRef target: subscribers) {
target.tell(msg, getSender());
}
}
}
}

Categories