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.
Related
Currently we have two separate API endpoints.
public Mono<ServerResponse> get(ServerRequest request) {
Sinks.StandaloneMonoSink<String> sink = Sinks.promise();
sinkMap.putIfAbsent(randomID, sink);
return sink.asMono().timeout(Duration.ofSeconds(60))
.flatMap(val -> ServerResponse.ok().body(BodyInserters.fromValue(val)))
}
public Mono<ServerResponse> push(ServerRequest request) {
Sinks.StandaloneMonoSink<String> sink = sinkMap.remove(randomID);
if (sink == null) {
return ServerResponse.notFound().build(); }
else {
return request.bodyToMono(String.class)
.flatMap(data -> {
sink.success(data);
return ServerResponse().ok().build();
}
}
}
The intention is for client to do a get request and to keep the connection open for 1 min or so waiting for some data to arrive. And then on push request data will be published to the open connection for get and the connection will close upon receipt of first element.
The issue with current approach is that the data may be emitted after get request times out and subscription is canceled, thus losing the data. Is it possible if no subscribers then if I try to emit item throw error or perform another action with data (from the push request side).
Thanks.
I had to read this question multiple times to understand what you are looking for!
I tried something like this and it seems to work.
private final DirectProcessor<String> processor = DirectProcessor.create();
private final FluxSink<String> sink = processor.sink();
// processor has a method to check if there are any active subscribers.
// if it is true, lets push data, otherwise we can throw exception / store it somehwere
#GetMapping("/push/{val}")
public boolean push(#PathVariable String val){
boolean status = processor.hasDownstreams();
if(status)
sink.next(val);
return status;
}
#GetMapping("/get")
public Mono<String> get(){
return processor
.next()
.timeout(Duration.ofMinutes(1));
}
Question:
Will you be running only one instance of this application? What will happen when you run multiple instances of this application?
For ex: User A might push the data to app-instance-1 and User B might subscribe to app-instance-2. In this case, User B might not get data. In this case, you might need something like Redis to store this data and share among all the instances for pub/sub behavior.
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());
}
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.
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.
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());
}
}
}
}