Akka routing with two router configs simultaneously - java

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).

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?

context().parent() in a router pool

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());
}

Implementing Content-Based Router Pattern in Akka

I am trying to implement a content-based router in my Akka actor system and according to this document the ConsistentHashingRouter is the way to go. After reading through its official docs, I still find myself confused as to how to use this built-in hashing router. I think that’s because the router itself is hash/key-based, and the example the Akka doc author chose to use was a scenario involving key-value based caches…so I can’t tell which keys are used by the cache and which ones are used by the router!
Let’s take a simple example. Say we have the following messages:
interface Notification {
// Doesn’t matter what’s here.
}
// Will eventually be emailed to someone.
class EmailNotification implements Notification {
// Doesn’t matter what’s here.
}
// Will eventually be sent to some XMPP client and on to a chatroom somewhere.
class ChatOpsNotifications implements Notification {
// Doesn’t matter what’s here.
}
etc. In theory we might have 20 Notification impls. I’d like to be able to send a Notification to an actor/router at runtime and have that router route it to the correct NotificationPubisher:
interface NotificationPublisher<NOTIFICATION implements Notification> {
void send(NOTIFICATION notification)
}
class EmailNotificationPublisher extends UntypedActor implements NotificationPubisher<EmailNotification> {
#Override
void onReceive(Object message) {
if(message instanceof EmailNotification) {
send(message as EmailNotification)
}
}
#Override
void send(EmailNotification notification) {
// Use Java Mail, etc.
}
}
class ChatOpsNotificationPublisher extends UntypedActor implements NotificationPubisher<ChatOpsNotification> {
#Override
void onReceive(Object message) {
if(message instanceof ChatOpsNotification) {
send(message as ChatOpsNotification)
}
}
#Override
void send(ChatOpsNotification notification) {
// Use XMPP/Jabber client, etc.
}
}
Now I could do this routing myself, manually:
class ReinventingTheWheelRouter extends UntypedActor {
// Inject these via constructor
ActorRef emailNotificationPublisher
ActorRef chatOpsNotificationPublisher
// ...20 more publishers, etc.
#Override
void onReceive(Object message) {
ActorRef publisher
if(message instanceof EmailNotification) {
publisher = emailNotificationPublisher
} else if(message instanceof ChatOpsNotification) {
publisher = chatOpsNotificationPublisher
} else if(...) { ... } // 20 more publishers, etc.
publisher.tell(message, self)
}
}
Or I could use the Akka-Camel module to defined a Camel-based router and send Notifications off to the Camel router, but it seems that Akka aready has this built-in solution, so why not use it? I just cant figure out how to translate the Cache example from those Akka docs to my Notification example here. What’s the purpose of the “key” in the ConsistentHashingRouter? What would the code look like to make this work?
Of course I would appreciate any answer that helps me solve this, but would greatly prefer Java-based code snippets if at all possible. Scala looks like hieroglyphics to me.
I agree that a Custom Router is more appropriate than ConsistentHashingRouter. After reading the docs on custom routers, it seems I would:
Create a GroupBase impl and send messages to it directly (notificationGroup.tell(notification, self)); then
The GroupBase impl, say, NotificationGroup would provide a Router instance that was injected with my custom RoutingLogic impl
When NotificationGroup receives a message, it executes my custom RoutingLogic#select method which determines which Routee (I presume some kind of an actor?) to send the message to
If this is correct (and please correct me if I’m wrong), then the routing selection magic happens here:
class MessageBasedRoutingLogic implements RoutingLogic {
#Override
Routee select(Object message, IndexedSeq<Routee> candidates) {
// How can I query the Routee interface and deterine whether the message at-hand is in fact
// appropriate to be routed to the candidate?
//
// For instance I'd like to say "If message is an instance of
// an EmailNotification, send it to EmailNotificationPublisher."
//
// How do I do this here?!?
if(message instanceof EmailNotification) {
// Need to find the candidate/Routee that is
// the EmailNotificationPublisher, but how?!?
}
}
}
But as you can see I have a few mental implementation hurdles to cross. The Routee interface doesn’t really give me anything I can intelligently use to decide whether a particular Routee (candidate) is correct for the message at hand.
So I ask: (1) How can I map messages to Routees (effectively performing the route selection/logic)? (2) How do I add my publishers as routees in the first place? And (3) Do my NotificationPublisher impls still need to extend UntypedActor or should they now implement Routee?
Here is a simple little A/B router in Scala. I hope this helps even though you wanted a Java based answer. First the routing logic:
class ABRoutingLogic(a:ActorRef, b:ActorRef) extends RoutingLogic{
val aRoutee = ActorRefRoutee(a)
val bRoutee = ActorRefRoutee(b)
def select(msg:Any, routees:immutable.IndexedSeq[Routee]):Routee = {
msg match{
case "A" => aRoutee
case _ => bRoutee
}
}
}
The key here is that I am passing in my a and b actor refs in the constructor and then those are the ones I am routing to in the select method. Then, a Group for this logic:
case class ABRoutingGroup(a:ActorRef, b:ActorRef) extends Group {
val paths = List(a.path.toString, b.path.toString)
override def createRouter(system: ActorSystem): Router =
new Router(new ABRoutingLogic(a, b))
val routerDispatcher: String = Dispatchers.DefaultDispatcherId
}
Same thing here, I am making the actors I want to route to available via the constructor. Now a simple actor class to act as a and b:
class PrintingActor(letter:String) extends Actor{
def receive = {
case msg => println(s"I am $letter and I received letter $msg")
}
}
I will create two instances of this, each with a different letter assignment so we can verify that the right ones are getting the right messages per the routing logic. Lastly, some test code:
object RoutingTest extends App{
val system = ActorSystem()
val a = system.actorOf(Props(classOf[PrintingActor], "A"))
val b = system.actorOf(Props(classOf[PrintingActor], "B"))
val router = system.actorOf(Props.empty.withRouter(ABRoutingGroup(a,b)))
router ! "A"
router ! "B"
}
If you ran this, you would see:
I am A and I received letter A
I am B and I received letter B
It's a very simple example, but one that shows one way to do what you want to do. I hope you can bridge this code into Java and use it to solve your problem.

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 (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