I'm having a very hard time understanding Akka's integration with the Play framework. I'd like to integrate Akka actors into a non controller library class of my own creation, but the documentation only provides an example in a controller returning a Result (Play 2.3). I don't have any code written yet because I'm so vexed on how to move forward. Does anyone have any examples on the proper usage of Akka outside a controller? I found this example (Java 8):
import play.libs.F.Promise;
import play.mvc.*;
import static play.libs.F.Promise.promise;
public class Application extends Controller {
public static Promise<Result> index() {
return promise(() -> longComputation())
.map((Integer i) -> ok("Got " + i));
}
}
but it looks like it has nothing to do with Akka at all. I'm so stumped I'm not even sure if I'm asking this question right, and I apologize for not having code samples.
My assumption is this: Place the above code sample in my library class and use it as specified, treating the "longRunningComputation()" as I would any other method call, and leave it at that. My concern at that point is that I'm not really leveraging what Akka has to offer.
Is there an Akka tutorial anyone would recommend to help here?
Overall
Please keep in mind that Akka is (practically) in no way related or restricted to Play. There are thousands of systems built on top of Akka which have nothing to do with Play. Akka and Play just play well together.
Akka + Play
It is perfectly fine to use Akka actors in the non-controller part of your application. You would just need a way to connect your controller to your actor system. This means you would need to find a way to talk to the actors in your actor system. There are (in general) two ways to do this in Akka. You either say (send) something to the actor or you ask him something.
tell
Saying / sending (also known as telling or fire-and-forget) is done in Java with actor.tell(message, getSelf()) and in Scala with actor ! message
import akka.actor.*;
import play.mvc.*;
import play.libs.Akka;
import play.libs.F.Promise;
import static akka.pattern.Patterns.ask;
public class Application extends Controller {
public static Result index() {
// select some actor from your system
ActorSelection actor = Akka.system().actorSelection("user/my-actor");
// now tell the actor something and do something else because we don't get a reply
actor.tell("Something");
return ok("Hello");
}
}
Of course you are in no way limited to contact the actor only from your controller's methods.
The whole process messaging process can be of course very complex - it totally depends on your business logic. The actor my-actor from above will now receive the message and do lots of stuff at this point - forward it, spawn children, kill itself, do calculations, etc.
In Java you will have an actor like:
import akka.actor.UntypedActor;
import akka.event.Logging;
import akka.event.LoggingAdapter;
public class MyUntypedActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
log.info("Received String message: {}", message);
// do whatever you want with this String message
} else
unhandled(message);
}
}
ask
Asking is done with ... surprise .. the ask pattern - in Scala with actor ? message.
You already have found an example how to do it in Java. Please keep in mind that this time you get something back. This is the so-called Future. Once this future completes (successfully) you will have your result. Then you can map this result to some other result. See now why the map() call is there?
import akka.actor.*;
import play.mvc.*;
import play.libs.Akka;
import play.libs.F.Promise;
import static akka.pattern.Patterns.ask;
public class Application extends Controller {
public static Promise<Result> index() {
// select some actor from your system
ActorSelection actor = Akka.system().actorSelection("user/my-actor");
// now ask the actor something and do something with the reply
return Promise.wrap(ask(actor, "how are you?", 1000))
.map(response -> ok(response.toString()));
}
}
Some notes from personal experience:
the Akka documentation is your friend
take a look at the WebSocket connections use cases - build yourself a demo Play app where you support WebSocket and every connection is handled by an actor. Now think of a chat application - once I send something on the WebSocket, I would like that every other user of the app receives it - now this is fine case for "hello-world-Akka actors", isn't it
Related
I have a request that is rather simple to formulate, but I cannot pull it of without leaking resources.
I want to return a response of type application/stream+json, featuring news events someone posted. I do not want to use Websockets, not because I don't like them, I just want to know how to do it with a stream.
For this I need to return a Flux<News> from my restcontroller, that is continuously fed with news, once someone posts any.
My attempt for this was creating a Publisher:
public class UpdatePublisher<T> implements Publisher<T> {
private List<Subscriber<? super T>> subscribers = new ArrayList<>();
#Override
public void subscribe(Subscriber<? super T> s) {
subscribers.add(s);
}
public void pushUpdate(T message) {
subscribers.forEach(s -> s.onNext(message));
}
}
And a simple News Object:
public class News {
String message;
// Constructor, getters, some properties omitted for readability...
}
And endpoints to publish news respectively get the stream of news
// ...
private UpdatePublisher<String> updatePublisher = new UpdatePublisher<>();
#GetMapping(value = "/news/ticker", produces = "application/stream+json")
public Flux<News> getUpdateStream() {
return Flux.from(updatePublisher).map(News::new);
}
#PutMapping("/news")
public void putNews(#RequestBody News news) {
updatePublisher.pushUpdate(news.getMessage());
}
This WORKS, but I cannot unsubscribe, or access any given subscription again - so once a client disconnects, the updatePublisher will just continue to push onto a growing number of dead channels - as I have no way to call the onCompleted() handler on the subscriptions.
TL;DL:
Can one push messages onto a possible endless Flux from a different thread and still terminate the Flux on demand without relying on a reset by peer exception or something along those lines?
You should never try to implement yourself the Publisher interface, as it boils down to getting the reactive streams implementation right. This is exactly the issue you're facing here.
Instead you should use one of the generator operators provided by Reactor itself (this is actually a Reactor question, nothing specific to Spring WebFlux).
In this case, Flux.create or Flux.push are probably the best candidates, given your code uses some type of event listener to push events down the stream. See the reactor project reference documentation on that.
Without more details, it's hard to give you a concrete code sample that solves your problem. Here are a few pointers though:
you might want to .share() the stream of events for all subscribers if you'd like some multicast-like communication pattern
pay attention to the push/pull/push+pull model that you'd like to have here; how is the backpressure supposed to work here? What if we produce more events that the subscribers can handle?
this model would only work on a single application instance. If you'd like this to work on multiple application instances, you might want to look into messaging patterns using a broker
I am coming to Akka after spending quite a bit of time over in Hystrix-land where, like Akka, failure is a first-class citizen.
In Hystrix, I might have a SaveFizzToDbCmd that attempts to save a Fizz instance to an RDB (MySQL, whatever), and a backup/“fallback” SaveFizzToMemoryCmd that saves that Fizz to an in-memory cache in case the primary (DB) command goes down/starts failing:
// Groovy pseudo-code
class SaveFizzToDbCmd extends HystrixCommand<Fizz> {
SaveFizzToMemoryCmd memoryFallback
Fizz fizz
#Override
Fizz run() {
// Use raw JDBC to save ‘fizz’ to an RDB.
}
#Override
Fizz getFallback() {
// This only executes if the ‘run()’ method above throws
// an exception.
memoryFallback.fizz = this.fizz
memoryFallback.execute()
}
}
In Hystrix, if run() throws an exception (say a SqlException), its getFallback() method is invoked. If enough exceptions get thrown within a certain amount of time, the HystrixCommands “circuit breaker” is “tripped” and only the getFallback() method will be invoked.
I am interested in accomplishing the same in Akka, but with actors. With Akka, we might have a JdbcPersistor actor and an InMemoryPersistor backup/fallback actor like so:
class JdbcPersistor extends UntypedActor {
#Override
void onReceive(Object message) {
if(message instanceof SaveFizz) {
SaveFizz saveFizz = message as SaveFizz
Fizz fizz = saveFizz.fizz
// Use raw JDBC to save ‘fizz’ to an RDB.
}
}
}
class InMemoryPersistor extends UntypedActor {
// Should be obvious what this does.
}
The problem I’m struggling with is:
How to get InMemoryPeristor correctly configured/wired as the backup to JdbcPersistor when it is failing; and
Failing back over to the JdbcPersistor if/when it “heals” (though it may never)
I would imagine this is logic that belongs inside JdbcPersistors SupervisorStrategy, but I can find nothing in the Akka docs nor any code snippets that implement this kind of behavior. Which tells me “hey, maybe this isn’t the way Akka works, and perhaps there’s a different way of doing this sort of circuit breaking/failover/failback in Akka-land.” Thoughts?
Please note: Java examples are enormously appreciated as Scala looks like hieroglyphics to me!
One way would be to have a FailoverPersistor actor which consuming code communicates with, that has both a JdbcPersistor and a InMemoryPeristor as children and a flag that decides which one to use and then basically routes traffic to the correct child depending on the state. The flag could then be manipulated by both the supervisor and timed logic/statistics inside the actor.
There is a circuit breaker in the contrib package of akka that might be an inspiration (or maybe even useable to achieve what you want): http://doc.akka.io/docs/akka/current/common/circuitbreaker.html
I've been learning Netty for a while, and from the Netty's tutorials(the MEAP book), almostly the examples are based on a fixed framework, like the EventLoop, Bootstrap, it seems that only the implementations of the handlers in the channelPipeline are the things we really should be concerned about.
Here I wanna design a simple chess game, based on a Server/Client mode, where two players are on different computers. And the background data I want to use Netty to transmit.(I just wanna practice using netty)
And in such a game, the front GUI detect the player put a chessman and then make some change to the data. Then, I need to deliver this data to the other player. And here comes the question.
I don't know how to implement a ChannelHandler in this situation, because in most examples, it seems that the data are not added dynamically by the handler. For instance, the data was created when channel was active by the method channelActive() or something else. All these methods was auto-invoked by Netty itself.
The only method I think is the write(). However, it seems that I have to call this method by myself if I implements this method, I don't know where I can get the parameter ChannelHandlerContext.
So, how to solve problems like this?
p.s.
I'm not so familiar with java network programming, nor the Netty. All the things I learn is based on the book, which I haven't finished reading yet. :)
Channel hander of Netty looks
package netty_sample;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
/**
* Server side action
*/
public class EchoServerHandler extends SimpleChannelHandler {
/**
* This method will be invoked when server recieved a message
*/
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) {
String msg = (String) event.getMessage(); // extract a message received
// You can write any code which handles the message, changes data, and create message for client, etc.
ctx.getChannel().write(someMessageToClient); // send back to client
}
}
As I understand, handler routine is invoked dynamically (in event-driven) when server received a message.
So code in the handler works dynamically, and you can write anything in the code.
I am working on an java application that will makes calls to a web service, I dont want to incur additional latency while making these calls hence I am planning on doing this asynchronously. Using threads is one way to go about it but this approach might become unreliable if the calls to the dependent service fail because of various reasons. So essentially what I am looking is some kind of in-process asynchronous service will fallback to temporarily store (inprocess database ?) and retry the failed requests. Are there are any exiting solutions out there that achieve this ? If not it would help if someone could point me to something that does a similar task like this.
Thanks
Actually, I've not yet tried it, but Reactor is something like Node.js and should allow you to program using event-driven paradigm.
Please check it out and let us know if it suits your needs.
Quarkus has easy built in reactive asynchronous call processing.
Like:
#ApplicationScoped
#RegisterForReflection
#Path("/")
public class JokesServiceCallManager {
private static final Logger LOGGER =
LoggerFactory.getLogger(JokesServiceCallManager.class);
#Inject
JokeResponseHandler jokeResponseHandler;
#Inject
JokeSetupAdapter jokesSetupAdapter;
#Inject
JokeReactionAdapter jokesReactionAdapter;
public Uni<Response> getData(String id,String correlationId) {
LOGGER.debug("********** getData(String id) id = " + id);
Uni<Response> uniSetup = jokesSetupAdapter.getByIdAsync(id);
Uni<Response> uniReaction =
jokesReactionAdapter.getByIdAsync(id);
return Uni.combine().all().unis(uniSetup, uniReaction )
.asTuple().onItem().transformToUni(tuple ->
jokeResponseHandler.createUniResponse(tuple.getItem1(),
tuple.getItem2()));
// .onFailure().invoke(exception ->
jokeResponseHandler.buildUniExceptionResponse(exception));
}
Which returns a tuple of all the calls when complete.
Simply allowing the service return to be cast to an Uni makes it all reactive (non-blocking)
The calls are as simple as :
import javax.ws.rs.core.Response;
import
org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.smallrye.mutiny.Uni;
#RegisterRestClient(configKey="setup-api")
#RegisterClientHeaders(SetupHeaderFactory.class)
public interface JokesSetupService {
#GET
#Path("/jokesetup/{id}")
#Produces(MediaType.APPLICATION_JSON)
Uni<Response> getByIdAsync(#PathParam("id") String id);
}
I am in the process of moving the business logic of my Swing program onto the server.
What would be the most efficient way to communicate client-server and server-client?
The server will be responsible for authentication, fetching and storing data, so the program will have to communication frequently.
it depends on a lot of things. if you want a real answer, you should clarify exactly what your program will be doing and exactly what falls under your definition of "efficient"
if rapid productivity falls under your definition of efficient, a method that I have used in the past involves serialization to send plain old java objects down a socket. recently I have found that, in combination with the netty api, i am able to rapidly prototype fairly robust client/server communication.
the guts are fairly simple; the client and server both run Netty with an ObjectDecoder and ObjectEncoder in the pipeline. A class is made for each object designed to handle data. for example, a HandshakeRequest class and HandshakeResponse class.
a handshake request could look like:
public class HandshakeRequest extends Message {
private static final long serialVersionUID = 1L;
}
and a handshake response may look like:
public class HandshakeResponse extends Message {
private static final long serialVersionUID = 1L;
private final HandshakeResult handshakeResult;
public HandshakeResponse(HandshakeResult handshakeResult) {
this.handshakeResult = handshakeResult;
}
public HandshakeResult getHandshakeResult() {
return handshakeResult;
}
}
in netty, the server would send a handshake request when a client connects as such:
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
Channel ch = e.getChannel();
ch.write(new HandshakeRequest();
}
the client receives the HandshakeRequest Object, but it needs a way to tell what kind of message the server just sent. for this, a Map<Class<?>, Method> can be used. when your program is run, it should iterate through the Methods of a class with reflection and place them in the map. here is an example:
public HashMap<Class<?>, Method> populateMessageHandler() {
HashMap<Class<?>, Method> temp = new HashMap<Class<?>, Method>();
for (Method method : getClass().getMethods()) {
if (method.getAnnotation(MessageHandler.class) != null) {
Class<?>[] methodParameters = method.getParameterTypes();
temp.put(methodParameters[1], method);
}
}
return temp;
}
this code would iterate through the current class and look for methods marked with an #MessageHandler annotation, then look at the first parameter of the method (the parameter being an object such as public void handleHandshakeRequest(HandshakeRequest request)) and place the class into the map as a key with the actual method as it's value.
with this map in place, it is very easy to receive a message and send the message directly to the method that should handle the message:
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
try {
Message message = (Message) e.getMessage();
Method method = messageHandlers.get(message.getClass());
if (method == null) {
System.out.println("No handler for message!");
} else {
method.invoke(this, ctx, message);
}
} catch(Exception exception) {
exception.printStackTrace();
}
}
there's not really anything left to it. netty handles all of the messy stuff allowing us to send serialized objects back and forth with ease. if you decide that you do not want to use netty, you can wrap your own protocol around java's Object Output Stream. you will have to do a little bit more work overall, but the simplicity of communication remains intact.
It's a bit hard to say which method is "most efficient" in terms of what, and I don't know your use cases, but here's a couple of options:
The most basic way is to simply use "raw" TCP-sockets. The upside is that there's nothing extra moving across the network and you create your protocol yourself, the latter being also a downside; you have to design and implement your own protocol for the communication, plus the basic framework for handling multiple connections in the server end (if there is a need for such).
Using UDP-sockets, you'll probably save a little latency and bandwidth (not much, unless you're using something like mobile data, you probably won't notice any difference with TCP in terms of latency), but the networking code is a bit harder task; UDP-sockets are "connectionless", meaning all the clients messages will end up in the same handler and must be distinguished from one another. If the server needs to keep up with client state, this can be somewhat troublesome to implement right.
MadProgrammer brought up RMI (remote method invocation), I've personally never used it, and it seems a bit cumbersome to set up, but might be pretty good in the long run in terms of implementation.
Probably one of the most common ways is to use http for the communication, for example via REST-interface for Web services. There are multiple frameworks (I personally prefer Spring MVC) to help with the implementation, but learning a new framework might be out of your scope for now. Also, complex http-queries or long urls could eat your bandwidth a bit more, but unless we're talking about very large amounts of simultaneous clients, this usually isn't a problem (assuming you run your server(s) in a datacenter with something like 100/100MBit connections). This is probably the easiest solution to scale, if it ever comes to that, as there're lots of load-balancing solutions available for web servers.