Implementing Content-Based Router Pattern in Akka - java

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.

Related

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.

Android Single observer with multiple subscribers in separate classes

ok, so i'm trying to implement rxJava2 with retrofit2. The goal is to make a call only once and broadcast the results to different classes. For exmaple: I have a list of geofences in my backend. I need that list in my MapFragment to dispaly them on the map, but I also need that data to set the pendingIntent service for the actual trigger.
I tried following this awnser, but I get all sorts of errors:
Single Observable with Multiple Subscribers
The current situation is as follow:
GeofenceRetrofitEndpoint:
public interface GeofenceEndpoint {
#GET("geofences")
Observable<List<Point>> getGeofenceAreas();
}
GeofenceDAO:
public class GeofenceDao {
#Inject
Retrofit retrofit;
private final GeofenceEndpoint geofenceEndpoint;
public GeofenceDao(){
InjectHelper.getRootComponent().inject(this);
geofenceEndpoint = retrofit.create(GeofenceEndpoint.class);
}
public Observable<List<Point>> loadGeofences() {
return geofenceEndpoint.getGeofenceAreas().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.share();
}
}
MapFragment / any other class where I need the results
private void getGeofences() {
new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError);
}
private void handleGeoResponse(List<Point> points) {
// handle response
}
private void handleGeoError(Throwable error) {
// handle error
}
What am I doing wrong, because when I call new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError); it's doing a separate call each time. Thx
new GeofenceDao().loadGeofences() returns two different instances of the Observable. share() only applies to the instance, not the the method. If you want to actually share the observable, you'd have to subscribe to the same instance. You could share the it with a (static) member loadGeofences.
private void getGeofences() {
if (loadGeofences == null) {
loadGeofences = new GeofenceDao().loadGeofences();
}
loadGeofences.subscribe(this::handleGeoResponse, this::handleGeoError);
}
But be careful not to leak the Obserable.
Maybe it's not answering your question directly, however I'd like to suggest you a little different approach:
Create a BehaviourSubject in your GeofenceDao and subscribe your retrofit request to this subject. This subject will act as a bridge between your clients and api, by doing this you will achieve:
Response cache - handy for screen rotations
Replaying response for every interested observer
Subscription between clients and subject doesn't rely on subscription between subject and API so you can break one without breaking another

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

Avoiding instanceof when checking a message type

I have the following situation where a client class executes different behavior based on the type of message it receives. I'm wondering if there is a better way of doing this since I don't like the instanceof and the if statements.
One thing I thought of doing was pulling the methods out of the client class and putting them into the messages. I would put a method like process() in the IMessage interface and then put the message specific behavior in each of the concrete message types. This would make the client simple because it would just call message.process() rather than checking types. However, the only problem with this is that the behavior contained in the conditionals has to do with operations on data contained within the Client class. Thus, if I did implement a process method in the concrete message classes I would have to pass it the client and I don't know if this really makes sense either.
public class Client {
messageReceived(IMessage message) {
if(message instanceof concreteMessageA) {
concreteMessageA msg = (concreteMessageA)message;
//do concreteMessageA operations
}
}
if (message instanceof concreteMessageB) {
concreteMessageb msg = (concreteMessageB)message;
//do concreteMessageB operations
}
}
The simple way to avoid instanceof testing is to dispatch polymorphicly; e.g.
public class Client {
void messageReceived(IMessage message) {
message.doOperations(this);
}
}
where each message class defines an appropriate doOperations(Client client) method.
EDIT: second solution which better matches the requirements.
An alternative that replaces a sequence of 'instanceof' tests with a switch statement is:
public class Client {
void messageReceived(IMessage message) {
switch (message.getMessageType()) {
case TYPE_A:
// process type A
break;
case TYPE_B:
...
}
}
}
Each IMessage class needs to define an int getMessageType() method to return the appropriate code. Enums work just as well ints, and are more more elegant, IMO.
One option here is a handler chain. You have a chain of handlers, each of which can handle a message (if applicable) and then consume it, meaning it won't be passed further down the chain. First you define the Handler interface:
public interface Handler {
void handle(IMessage msg);
}
And then the handler chain logic looks like:
List<Handler> handlers = //...
for (Handler h : handlers) {
if (!e.isConsumed()) h.handle(e);
}
Then each handler can decide to handle / consume an event:
public class MessageAHandler implements Handler {
public void handle(IMessage msg) {
if (msg instanceof MessageA) {
//process message
//consume event
msg.consume();
}
}
}
Of course, this doesn't get rid of the instanceofs - but it does mean you don't have a huge if-elseif-else-if-instanceof block, which can be unreadable
What type of message system are you using?
Many have options to add a filter to the handlers based on message header or content. If this is supported, you simply create a handler with a filter based on message type, then your code is nice and clean without the need for instanceof or checking type (since the messaging system already checked it for you).
I know you can do this in JMS or the OSGi event service.
Since you are using JMS, you can basically do the following to register your listeners. This will create a listener for each unique message type.
String filterMsg1 = "JMSType='messageType1'";
String filterMsg2 = "JMSType='messageType2'";
// Create a receiver using this filter
Receiver receiverType1 = session.createReceiver(queue, filterMsg1);
Receiver receiverType2 = session.createReceiver(queue, filterMsg2);
receiverType1.setMessageHandler(messageType1Handler);
receiverType2.setMessageHandler(messageType2Handler);
Now each handler will receive the specific message type only (no instanceof or if-then), assuming of course that the sender sets the type via calls to setJMSType() on the outgoing message.
This method is built into message, but you can of course create your own header property and filter on that instead as well.
//Message.java
abstract class Message{
public abstract void doOperations();
}
//MessageA.java
class MessageA extends Message{
public void doOperations(){
//do concreteMessageA operations ;
}
}
//MessageB.java
class MessageB extends Message {
public void doOperations(){
//do concreteMessageB operations
}
}
//MessageExample.java
class MessageExample{
public static void main(String[] args) {
doSmth(new MessageA());
}
public static void doSmth(Message message) {
message.doOperations() ;
}
}
A Java 8 solution that uses double dispatch. Doesn't get rid of instanceof completely but does only require one check per message instead of an if-elseif chain.
public interface Message extends Consumer<Consumer<Message>> {};
public interface MessageA extends Message {
#Override
default void accept(Consumer<Message> consumer) {
if(consumer instanceof MessageAReceiver){
((MessageAReceiver)consumer).accept(this);
} else {
Message.super.accept(this);
}
}
}
public interface MessageAReceiver extends Consumer<Message>{
void accept(MessageA message);
}
With JMS 2.0 you can use:
consumer.receiveBody(String.class)
For more information you can refer here:

Categories