I'm just beginning with AKKA and have a basic question about how non-actor code talks to actor code.
How can non-actor code call an actor and get a response ? I've tried calling the actor from the non-actor using Patterns.ask but this doesn't work because there is no 'sender' to which the actor can respond.
So how am I supposed to do it ?
This should work just fine. When you use ask, a lightweight actor (I believe represented by a PromiseActorRef) is created to represent the sender so that a response can be sent back that will complete the Future that is created via ask. A little example to show this in action. First the test actor:
class TestActor extends UntypedActor{
public TestActor(){
}
public void onReceive(Object msg){
getContext().sender().tell("bar", getContext().self());
}
}
Then the non-actor code that will call it
import java.util.concurrent.TimeUnit;
import scala.concurrent.Await;
import scala.concurrent.Future;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.pattern.Patterns;
import akka.util.Timeout;
public class AskTest {
public static void main(String[] args) throws Exception{
ActorSystem sys = ActorSystem.apply("test");
ActorRef ref = sys.actorOf(Props.create(TestActor.class), "mytest");
Timeout t = new Timeout(5, TimeUnit.SECONDS);
Future<Object> fut = Patterns.ask(ref, "foo", t);
String response = (String)Await.result(fut, t.duration());
System.out.println(response);
}
}
Related
Requirement: I need to get all the messages from all the sessions from the queue. registerSessionHandler should consume messages as soon as they appear in the queue.
Issue: the code accepts the messages that are pertaining to one of the session id (xyz) and then it just waits. And even when more messages are pushed with that session id (xyz), it fails to consume it.
Any suggestions - what obvious thing I am missing here.
I have registerSessionHandler for receiving session messages continuously from the queue. Whenever i start new session, i am getting message of only one sessionID.
Test Queue: In this queue, there are 20 messages available with 4 different sessionIDs. Whenever i run Java application (QueueSessionReceiveTest.java), i get only 5 messages which is associated with single session ID.
MAVEN - azure-servicebus - 1.1.1
RECEIVE CODE:
import java.time.Duration;
import com.microsoft.azure.servicebus.IMessage;
import com.microsoft.azure.servicebus.IQueueClient;
import com.microsoft.azure.servicebus.QueueClient;
import com.microsoft.azure.servicebus.ReceiveMode;
import com.microsoft.azure.servicebus.SessionHandlerOptions;
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder;
public class QueueSessionReceiveTest {
private static final String connectionString = "Endpoint=sb://XXXXXX";
private static final String queueName = "test";
private static IQueueClient queueClient;
public static void main(String[] args) throws Exception {
queueClient = new QueueClient(new ConnectionStringBuilder(connectionString, queueName), ReceiveMode.PEEKLOCK);
queueClient.registerSessionHandler(new QueueMessageSessionHandler(), new SessionHandlerOptions(1, false, Duration.ofMinutes(1)));
}}
SESSION HANDLER CODE:
import java.util.concurrent.CompletableFuture;
import com.microsoft.azure.servicebus.ExceptionPhase;
import com.microsoft.azure.servicebus.IMessage;
import com.microsoft.azure.servicebus.IMessageSession;
import com.microsoft.azure.servicebus.IQueueClient;
import com.microsoft.azure.servicebus.ISessionHandler;
public class QueueMessageSessionHandler implements ISessionHandler {
#Override
public CompletableFuture<Void> onMessageAsync(IMessageSession session, IMessage iMessage) {
return session.completeAsync(iMessage.getLockToken()).thenRunAsync(() -> Logger.debug("some log") );
}
#Override
public CompletableFuture<Void> OnCloseSessionAsync(IMessageSession session) {
return null;
}
#Override
public void notifyException(Throwable exception, ExceptionPhase exceptionPhase) {
// Do nothing
}}
Please refer below link for solution.
https://github.com/Azure/azure-service-bus-java/issues/187
I am using Akka websockets to push data to some client.
This is what I have done so far:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.Http;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.model.ws.Message;
import akka.http.javadsl.model.ws.WebSocket;
import akka.japi.Function;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
public class Server {
public static HttpResponse handleRequest(HttpRequest request) {
System.out.println("Handling request to " + request.getUri());
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeterHello();
return WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
return HttpResponse.create().withStatus(404);
}
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
try {
final Materializer materializer = ActorMaterializer.create(system);
final Function<HttpRequest, HttpResponse> handler = request -> handleRequest(request);
CompletionStage<ServerBinding> serverBindingFuture = Http.get(system).bindAndHandleSync(handler,
ConnectHttp.toHost("localhost", 8080), materializer);
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
}
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSource(Sink.ignore(),
Source.single(new akka.http.scaladsl.model.ws.TextMessage.Strict("Hello!")));
}
}
At the client side, I am successfully receiving a 'Hello!' message.
However, now I want to send data dynamically (preferably from an Actor), something like this:
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
public class PushActor extends UntypedActor {
#Override
public void onReceive(Object message) {
if (message instanceof String) {
String statusChangeMessage = (String) message;
// How to push this message to a socket ??
} else {
System.out.println(String.format("'%s':\nReceived unknown message '%s'!", selfActorPath, message));
}
}
}
I am unable to find any example regarding this online.
The following is the software stack being used:
Java 1.8
akka-http 10.0.10
One - not necessarily very elegant - way of doing this is to use Source.actorRef and send the materialized actor somewhere (maybe a router actor?) depending on your requirements.
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSourceMat(Sink.ignore(),
Source.actorRef(100, OverflowStrategy.fail()),
Keep.right()).mapMaterializedValue( /* send your actorRef to a router? */);
}
Whoever receives the actorRefs of the connected clients must be responsible for routing messages to them.
Main class for Subscriber: Application.java
package com.mynamespace;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.contrib.pattern.DistributedPubSubExtension;
import akka.contrib.pattern.DistributedPubSubMediator;
import com.mynamespace.actors.SubscriberActor;
#SpringBootApplication
#ComponentScan(basePackages = "com.mynamespace.*")
public class Application {
public static void main(String[] args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
// get hold of the actor system
ActorSystem system = ctx.getBean(ActorSystem.class);
ActorRef mediator = DistributedPubSubExtension.get(system).mediator();
ActorRef subscriber = system.actorOf(
Props.create(SubscriberActor.class), "subscriber");
// subscribe to the topic named "content"
mediator.tell(new DistributedPubSubMediator.Put(subscriber), subscriber);
// subscriber.tell("init", null);
System.out.println("Running.");
Thread.sleep(5000l);
}
}
Subscriber actor: SubscriberActor.java
package com.mynamespace.actors;
import java.util.ArrayList;
import java.util.List;
import akka.actor.UntypedActor;
import com.mynamespace.message.CategoryServiceRequest;
import com.mynamespace.message.CategoryServiceResponse;
public class SubscriberActor extends UntypedActor {
#Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof CategoryServiceRequest) {
System.out.println("Request received for GetCategories.");
CategoryServiceResponse response = new CategoryServiceResponse();
List<String> categories = new ArrayList<>();
categories.add("Food");
categories.add("Fruits");
response.setCatgories(categories);
getSender().tell(response, getSelf());
} else if (msg instanceof String && msg.equals("init")) {
System.out.println("init called");
} else {
System.out
.println("Unhandelled message received for getCategories.");
}
}
}
Application.conf for subscriber
akka {
loglevel = INFO
stdout-loglevel = INFO
loggers = ["akka.event.slf4j.Slf4jLogger"]
extensions = ["akka.contrib.pattern.DistributedPubSubExtension"]
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 0
}
}
cluster {
seed-nodes = [
"akka.tcp://mynamespace-actor-system#127.0.0.1:2551",
"akka.tcp://mynamespace-actor-system#127.0.0.1:2552"]
auto-down-unreachable-after = 10s
}
}
Main class for publisher: Application.java
package com.mynamespace;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.contrib.pattern.DistributedPubSubExtension;
import akka.contrib.pattern.DistributedPubSubMediator;
import com.mynamespace.actors.PublisherActor;
#SpringBootApplication
#ComponentScan(basePackages = "com.mynamespace.*")
public class Application {
public static void main(String[] args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
// get hold of the actor system
ActorSystem system = ctx.getBean(ActorSystem.class);
ActorRef mediator = DistributedPubSubExtension.get(system).mediator();
ActorRef publisher = system.actorOf(Props.create(PublisherActor.class),
"publisher");
mediator.tell(new DistributedPubSubMediator.Put(publisher), publisher);
Thread.sleep(5000);
publisher.tell("hi", publisher);
System.out.println("Running.");
}
}
PublisherActor.java
package com.mynamespace.actors;
import scala.concurrent.Future;
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.contrib.pattern.DistributedPubSubExtension;
import akka.contrib.pattern.DistributedPubSubMediator;
import akka.dispatch.Mapper;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.mynamespace.message.CategoryServiceRequest;
import com.mynamespace.message.CategoryServiceResponse;
public class PublisherActor extends UntypedActor {
// activate the extension
ActorRef mediator = DistributedPubSubExtension.get(getContext().system())
.mediator();
public void onReceive(Object msg) {
if (msg instanceof String) {
Timeout timeOut = new Timeout(50000l);
mediator.tell(new DistributedPubSubMediator.Send(
"/user/subscriber", new CategoryServiceRequest()),
getSelf());
Future<Object> response = Patterns.ask(mediator,
new DistributedPubSubMediator.Send("/user/subscriber",
new CategoryServiceRequest()), timeOut);
Future<CategoryServiceResponse> finalresponse = response.map(
new Mapper<Object, CategoryServiceResponse>() {
#Override
public CategoryServiceResponse apply(Object parameter) {
CategoryServiceResponse responseFromRemote = (CategoryServiceResponse) parameter;
System.out.println("received:: list of size:: "
+ responseFromRemote.getCatgories().size());
return responseFromRemote;
}
}, getContext().system().dispatcher());
} else if (msg instanceof DistributedPubSubMediator.SubscribeAck) {
System.out.println("subscribbed.......");
} else {
unhandled(msg);
}
}
}
Application conf for publisher is same as of subscriber. Both are running on different ports on the same system.
I have two seed nodes defined and running on my local system. Somehow I am not able to ASK/TELL subscriber from producer (both running on different nodes) via DistributedPubSub Mediator.
After running Subscriber then publisher: I don't get any exceptions or any dead letter references printed in stdout/logs.
Is it possible to be able to view what actor references my mediator holds?
Need help to find issues or possible issues.
I had the same problem, after the comments from #spam and my own experiments the thing I can recommend is to use Publish/Subscribe with groups and sendOneMessageToEachGroup=true.
Is it supposed that the Send only works locally? if so the documentation doesn't explicit that. But I can also tell by the code there that this specific part of the documentation has been overlooked apparently (as change the Class names but then don't invoke those, invoke the previous ones on the previous examples)
Hope this helps anyone that has this issue, as the docs are a bit misleading apparently
I´m very new to Akka. I have created a simple Hello World App using it.
The App is very simple, it sends a message to my simple Actor. What I want is to send a message back to the first sender of the message. I can´t get the return message. How can someone do that? Do the client have to implement a onReceive method? I have tried to comment in the code.
import akka.actor.UntypedActor;
public class HelloActor extends UntypedActor {
#Override
public void onReceive(Object o) throws Exception {
if(o instanceof String){
String message = (String)o;
System.out.println(message);
// how to get this response ?
getSender().tell("World",getSelf());
}
}
}
The Client
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class Client{
public static void main(String[] args){
ActorSystem actorSystem = ActorSystem.create("HelloWorldSystem");
ActorRef listener = actorSystem.actorOf(new Props(HelloActor.class), "listener");
// sending is OK but how to get the response?
listener.tell("Hello");
}
}
The correct answer is to use a Future:
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.dispatch.*;
import akka.dispatch.Future;
import akka.pattern.Patterns;
import akka.util.Duration;
import akka.util.Timeout;
public class Client{
public static void main(String[] args){
ActorSystem actorSystem = ActorSystem.create("HelloWorldSystem");
ActorRef listener = actorSystem.actorOf(new Props(HelloActor.class), "listener");
Timeout timeout = new Timeout(Duration.create(5, "seconds"));
Future<Object> future = Patterns.ask(listener, "Hello", timeout);
try{
String result = (String) Await.result(future, timeout.duration());
System.out.println(result);
}catch (Exception e){
e.printStackTrace();
}
}
}
I am trying to use Akka future with play framework to connect to a remote akka system
. After running the system the akka future gives me a warning that one argument is left.
the code are below :
this is the [lay controller code:
p
ackage controllers;
import com.typesafe.config.ConfigFactory;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import play.*;
import play.mvc.*;
import views.html.*;
public class Application extends Controller {
public static Result index() throws InterruptedException {
System.out.println(" Local Node Called0");
ActorSystem csystem = ActorSystem.create("Application", ConfigFactory.load().getConfig("LocalNode"));
ActorRef localNode = csystem.actorOf(new Props(LocalNode.class));
System.out.println(" Local Node Called1");
localNode.tell("Hello");
System.out.println(" Local Node Called2");
Thread.sleep(5000);
csystem.shutdown();
return ok(index.render("I am OK"));
}
}
this is the play framework local actor node
package controllers;
import akka.actor.;
import akka.dispatch.Await;
import akka.dispatch.Future;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.util.Duration;
import akka.util.Timeout;
import akka.pattern.;
public class LocalNode extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
Timeout timeout = new Timeout(Duration.parse("20 seconds"));
ActorRef masterActor;
public void preStart()
{
/* Get reference to Master Node*/
masterActor =
getContext().actorFor("akka://MasterNode#127.0.0.1:2552/user/masterActor");
}
#Override
public void onReceive(Object message) throws Exception {
System.out.println(" Future called ");
Future<Object> future = Patterns.ask(masterActor , message.toString(), timeout);
String result = (String) Await.result(future, timeout.duration());
log.info("Messagefrom Server", result.toString());
}
}
this is the remote akka system master nide
package Rubine_Cluster;
import com.typesafe.config.ConfigFactory;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.kernel.Bootable;
/**
* Hello world!
*
*/
public class MasterNode implements Bootable
{
final ActorSystem system;
public MasterNode() {
system = ActorSystem.create("MasterNode", ConfigFactory.load()
.getConfig("masterNode"));
ActorRef masterActor = system.actorOf(new Props(MasterActor.class),"masterActor");
System.out.println(" Master Node is called ");
}
public void startup() {
}
public void shutdown() {
system.shutdown();
}
}
this is the akka remote system MasterActor
package Rubine_Cluster;
import akka.actor.*;
public class MasterActor extends UntypedActor {
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
// Get reference to the message sender and reply back
getSender().tell(message + " got something");
}
}
}
this is the message from the play framewrok
[INFO] [09/30/2012 16:47:25.669] [Application-akka.actor.default-dispatcher-1] [
akka://Application/user/$a] Messagefrom Server WARNING arguments left: 1
help is needed cos I am suppose to meet the assignment deadline
thanks to all
The "arguments left: 1" warning is due to the following line:
log.info("Messagefrom Server", result.toString())
You're passing unused params to the logger. It should be this instead:
log.info("Messagefrom Server {}", result.toString())
Try to give a name to your actor in Play:
ActorRef localNode = csystem.actorOf(new Props(LocalNode.class), "localNode");
And also note that if you need to access the Akka system from Play, it is better to use:
ActorSystem csystem = Akka.system();
instead of:
ActorSystem csystem = ActorSystem.create("Application", ConfigFactory.load().getConfig("LocalNode"));