Proper way to maintain an SSE connection in Play - scala

I would like to maintain an SSE pipeline in the front end of my Play 2.7.x application, which would listen indefinitely for some irregularly spaced events from server (possibly triggered by other users). I send the events via a simple Akka flow, like this:
Ok.chunked(mySource via EventSource.flow).as(ContentTypes.EVENT_STREAM)
However the connection is automatically closed by Play/Akka server. What would be the best course of action here:
set play.server.http.idleTimeout to infinite (but documentation
does not recommend it; also it would affect other non-SSE endpoints)?
rely on browser to automatically reestablish the connection (but as far as I know not all browsers do it)?
explicitly implement some reconnection logic in Javascript on the client?
perhaps idleTimeout can be overridden locally for a specific action (I have not found a way though)?

Periodically send an empty Event to keep the connection alive:
import scala.concurrent.duration._
val heartbeat = Event("", None, None)
val sseSource =
mySource
.via(EventSource.flow)
.keepAlive(1.second, () => heartbeat)
Ok.chunked(sseSource).as(ContentTypes.EVENT_STREAM)
Akka HTTP's support for server-sent events demonstrates the same approach (Play internally uses Akka HTTP).

Related

Akka Actor Searching and Streaming Events

I have a scenario where I have a bunch of Akka Actors running with each Actor representing an IoT device. I have a web application based on Play inside which these Actors are running and are connected to these IoT devices.
Now I want to expose the signals from there Actors to the outside world by means of a WebSocket Endpoint. Each of the Actor has some sort of mechanism with which I can ask for the latest signal status.
My idea is to do the following:
Add a WebSocket endpoint in my controller which expects the id of the IoT device for which it needs the signals. In this controller, I will do an actor selection to get the Actor instance that corresponds to the id of the IoT device that is passed in.
Use the ActorRef obtained in step 1 and instantiate the WebSocketActor
In this WebSocketActor, I will instantiate a Monix Observable that will at regular intervals use the actorRef and ask it for the signals.
As soon as I get these signals, I will pass it on to the WebSocket endpoint
Now my question is:
What happens say if a client has opened a WebSocket stream and after some time the Actor representing the IoT device is dead. I probably should handle this situation in my WebSocketActor. But how would this look like?
If the Actor representing the IoT device comes back alive (assuming that I have some supervison set up), can I continue processing the client that opened the socket connection before the Actor was dead? I mean will the client need to somehow close and open the connection again?
Please suggestions?
If you'd like to see an Akka actors + Monix integration example, communicating over WebSocket, look no further than the monix-sample project.
The code handles network failure. If you'll load that sample in the browser, disconnect the network and you'll see it recover once connectivity is back on.

What happens to messages that come to a server implements stream processing after the source reached its bound?

Im learning akka streams but obviously its relevant to any streaming framework :)
quoting akka documentation:
Reactive Streams is just to define a common mechanism of how to move
data across an asynchronous boundary without losses, buffering or
resource exhaustion
Now, from what I understand is that if up until before streams, lets take an http server for example, the request would come and when the receiver wasent finished with a request, so the new requests that are coming will be collected in a buffer that will hold the waiting requests, and then there is a problem that this buffer have an unknown size and at some point if the server is overloaded we can loose requests that were waiting.
So then stream processing came to play and they bounded this buffer to be controllable...so we can predefine the number of messages (requests in my example) we want to have in line and we can take care of each at a time.
my question, if we implement that a source in our server can have a 3 messages at most, so if the 4th id coming what happens with it?
I mean when another server will call us and we are already taking care of 3 requests...what will happened to he's request?
What you're describing is not actually the main problem that Reactive Streams implementations solve.
Backpressure in terms of the number of requests is solved with regular networking tools. For example, in Java you can configure a thread pool of a networking library (for example Netty) to some parallelism level, and the library will take care of accepting as much requests as possible. Or, if you use synchronous sockets API, it is even simpler - you can postpone calling accept() on the server socket until all of the currently connected clients are served. In either case, there is no "buffer" on either side, it's just until the server accepts a connection, the client will be blocked (either inside a system call for blocking APIs, or in an event loop for async APIs).
What Reactive Streams implementations solve is how to handle backpressure inside a higher-level data pipeline. Reactive streams implementations (e.g. akka-streams) provide a way to construct a pipeline of data in which, when the consumer of the data is slow, the producer will slow down automatically as well, and this would work across any kind of underlying transport, be it HTTP, WebSockets, raw TCP connections or even in-process messaging.
For example, consider a simple WebSocket connection, where the client sends a continuous stream of information (e.g. data from some sensor), and the server writes this data to some database. Now suppose that the database on the server side becomes slow for some reason (networking problems, disk overload, whatever). The server now can't keep up with the data the client sends, that is, it cannot save it to the database in time before the new piece of data arrives. If you're using a reactive streams implementation throughout this pipeline, the server will signal to the client automatically that it cannot process more data, and the client will automatically tweak its rate of producing in order not to overload the server.
Naturally, this can be done without any Reactive Streams implementation, e.g. by manually controlling acknowledgements. However, like with many other libraries, Reactive Streams implementations solve this problem for you. They also provide an easy way to define such pipelines, and usually they have interfaces for various external systems like databases. In particular, such libraries may implement backpressure on the lowest level, down to to the TCP connection, which may be hard to do manually.
As for Reactive Streams itself, it is just a description of an API which can be implemented by a library, which defines common terms and behavior and allows such libraries to be interchangeable or to interact easily, e.g. you can connect an akka-streams pipeline to a Monix pipeline using the interfaces from the specification, and the combined pipeline will work seamlessly and supporting all of the backpressure features of Reacive Streams.

Moving from socko to akka-http websockets

I have an existing akka application built on socko websockets. Communication with the sockets takes place inside a single actor and messages both leaving and entering the actor (incoming and outgoing messages, respectively) are labelled with the socket id, which is a first class property of a socko websocket (in socko a connection request arrives labelled with the id, and all the lifecycle transitions such as handshaking, disconnection, incoming frames etc. are similarly labelled)
I'd like to reimplement this single actor using akka-http (socko is more-or-less abandonware these days, for obvious reasons) but it's not straightforward because the two libraries are conceptually very different; akka-http hides the lower level details of the handshaking, disconnection etc, simply sending whichever actor was bound to the http server an UpgradeToWebsocket request header. The header object contains a method that takes a materialized Flow as a handler for all messages exchanged with the client.
So far, so good; I am able to receive messages on the web socket and reply them directly. The official examples all assume some kind of stateless request-reply model, so I'm struggling with understanding how to make the next step to assigning a label to the materialized flow, managing its lifecycle and connection state (I need to inform other actors in the application when a connection is dropped by a client, as well as label the messages.)
The alternative (remodelling the whole application using akka-streams) is far too big a job, so any advice about how to keep track of the sockets would be much appreciated.
To interface with an existing actor-based system, you should look at Source.actorRef and Sink.actorRef. Source.actorRef creates an ActorRef that you can send messages to, and Sink.actorRef allows you to process the incoming messages using an actor and also to detect closing of the websocket.
To connect the actor created by Source.actorRef to the existing long-lived actor, use Flow#mapMaterializedValue. This would also be a good place to assign an unique id for a socket connection.
This answer to a related question might get you started.
One thing to be aware of. The current websocket implementation does not close the server to client flow when the client to server flow is closed using a websocket close message. There is an issue open to implement this, but until it is implemented you have to do this yourself. For example by having something like this in your protocol stack.
The answer from RĂ¼diger Klaehn was a useful starting point, thanks!
In the end I went with ActorPublisher after reading another question here (Pushing messages via web sockets with akka http).
The key thing is that the Flow is 'materialized' somewhere under the hood of akka-http, so you need to pass into UpgradeToWebSocket.handleMessagesWithSinkSource a Source/Sink pair that already know about an existing actor. So I create an actor (which implements ActorPublisher[TextMessage.Strict]) and then wrap it in Source.fromPublisher(ActorPublisher(myActor)).
When you want to inject a message into the stream from the actor's receive method you first check if totalDemand > 0 (i.e. the stream is willing to accept input) and if so, call onNext with the contents of the message.

Use Ack on chunked responses with Spray

I'm using spray-can 1.2.1.
I'm streaming big files from/to a storage, I use both chunked requests and chunked responses for that.
For chunk requests I use the built-in ack mechanism in my actor to make sure each chunk has been written before sending more:
connection ! MessageChunk(data).withAck(ChunkSent)
connection is the IO actor provided by Spray and Akka, then I can wait for a ChunkSent before sending the next chunk. Good.
I'm struggling to reproduce the same behavior with chunked responses. I can send my HttpRequest and then receive a ChunkedResponseStart, followed by a bunch of MessageChunks and finally a ChunkedMessageEnd but is there a way to force Spray to wait for me to send an ack after each MessageChunk before sending the next one?
Edit: Just to be a bit more clear: I use spray-can as a client in this case, I am not the server, the server is the storage I mentioned before.
Well put question. Currently, you cannot make spray (1.x.1) wait for Acks before continuing to read.
What you can do however is to send Tcp.SuspendReading and Tcp.ResumeReading commands to the client connection (sender of chunks) to instruct the Akka IO TCP layer to stop reading while you are overloaded. See this proof-of-concept which tries to add Acking for the receive side (for the server but should work similarly for the client side) on top of SuspendReading/ResumeReading for hints about how to build something with the current version of spray.
This situation is clearly not optimal because especially under load 1) you need to figure out that you are overloaded and 2) those message may be stuck in the message queue of the TCP connection before they will be handled.
There are two things that will improve the situation in the future:
Since recently Akka IO supports a "pull mode" where the TCP connection will only ever read once and then wait for a Tcp.ResumeReading command (basically an Ack). However, this is not available for use in spray (and probably won't be).
What we are focusing on right now for Akka HTTP is streaming support. The plan is to introduce a new API (next to what we have in spray-can) that makes working with streams natural for HTTP and which will support automatic back-pressure support without any need for extra user code to support it. Alas, it is not yet ready.

Play framework: service to service continuous communication

I need some advice/insight how to best implement certain functionality. The idea of my task is live system monitoring dashboard.
Let's say I have a following setup based on two physical servers:
Server1 is running Play application which monitors certain files, services, etc for changes. As soon as change occurs it alerts another Play application running on Server2.
Server2 is running a Play application that serves a web front end displaying live dashboard data being sent to it from Play application sitting on Server1.
I am only familiar with Play framework in a way that it serves data to http requests, but the way I need it to run in this particular situation is a bit different.
My question is how do I keep these two Play applications in constant connection the way I've described above? The requirement is that Server1 application would be pushing data to Server2 application on a need basis as opposed to Server2 application running in an endless loop and asking Server1 application if there is any new data every 5 seconds.
I'm using Play Framework 2.2.1 with Scala.
Actually Akka introduced in Play 2.0 perfectly fits your requirements (as Venkat pointed).
Combining its remoting, scheduler and futures possibilities you will be able to build every monitor you need.
Scanerio may be ie:
S1 let's name it a Doctor uses Akka's scheduler to monitor resources each several seconds
if Doctor detects changes sends Akka message to S2's actor (FrontEnd) otherwise does nothing.
Mentioned actor of FrontEnd can add event to some queue, or push it directly ie to some WebSocket, which will push it to browser. Other option is setting another scheduler at FrontEnd which will check if queue contains new events.
Check included sample applications how you can communicate your FrontEnd with browser (ie. commet-live-monitoring or eventsource-clock).
For communication between a Doctor and FrontEnd apps, akka-remote is promising feature.
I think Server-Sent Events (SSE: http://dev.w3.org/html5/eventsource/) are what you are looking for. Since it's supposed to be only one-directional push (server1 pushes data to server2), SSE is probably a better choice over WebSockets which are full-duplex bidirectional connections. Since your Server2 has a web-front end, the browser can automatically reconnect to Server1 if you are using SSE. Most modern browsers support SSE (IE doesn't).
Since you are using Play Framework: You can use Play WS API for Service to Service communication and also you can take advantage of the powerful abstractions for handling data asynchronously like Enumerator and Iteratee. As Play! integrates seamlessly with Akka, you can manage/supervise the HTTP connection using Actors.
Edit:
Answering "How exactly one service can push data to another on a need basis" in steps:
Manage the HTTP connection: Server1 needs to have a WebService client to manage HTTP connection with Server2. By "manage HTTP connection" I mean: reconnect/reset/disconnect the HTTP connection. Akka Actors are a great usecase for solving this problem. Basically this actor receives messages like CONNECT, CHECK_CONN_STATUS, DISCONNECT, RESET etc. Have a scheduler for your HttpSupervisor actor to check the connection status, so that you can reconnect if the connection is dead.
val system = ActorSystem("Monitor")
val supervisorRef = system.actorOf(Props(new HttpSupervisor(system.eventStream)), "MonitorSupervisor")
system.scheduler.schedule(60 seconds, 60 seconds, supervisorRef, CHECK_CONN_STATUS)
Listen to the changes and PUSH on need:
Create an Enumerator which produces the changes. Create an Iteratee for consuming the changes asynchronously. Again, some code that may be of help:
val monitorIteratee = play.api.libs.iteratee.Iteratee.foreach[Array[Byte]]
(WS.url(postActionURLOnServer2).post(new String(_, "UTF-8")))
Attach the iteratee to the enumerator.