0
votes

I want to redirect a websocket connection to another instance of play but haven't figured out how to do it yet.

Basically I have an akka cluster with load balancing between the nodes and actors (with akka routers), so far so good, it's working.

Because of this I need to receive a websocket connection in one instance of play, but i want to use the router (akka actor) to forward it to another instance of play. This is important because with this I achieve my load balancing requirement.

A tipical route that accepts websocket connections looks like this:

def socket = WebSocket.accept[JsValue, JsValue] { request =>
    ActorFlow.actorRef(out => MyWebSocketActor.props(out))
}

The problem is that this immediately returns a Flow (akka streams) and establishes the websocket connection and i need to forward the request and established the connection in another instance of Play. This forwarding must go through the actors in order to maintain the load balancing. I can forward the messages just fine, but I need to forward the initial connection.

Any help is appreciated, thanks.

1

1 Answers

1
votes

Found the solution from botkop in this post. And according to akka http documentation appears to be a correct one (there are other methods, but are either more complicated or being deprecated)

Websocket Proxy using Play 2.6 and akka streams

def websocketFlow: Flow[Message, Message, Future[WebSocketUpgradeResponse]] =
   Http().webSocketClientFlow(WebSocketRequest("ws://localhost:9000/upper-socket"))

def proxySocket: WebSocket = WebSocket.accept[String, String] { _ =>
   Flow[String].map(s => TextMessage(s))
     .via(websocketFlow)
     .map(_.asTextMessage.getStrictText)
}

The above works in redirecting to a static URL which can be another play instance or not. This other instance can implement websockets as if it was a stand alone solution.

In my case I need load balancing so, adding to the above, in method "websocketFlow" I first need to use a akka actor, which is a router in a cluster and ask it for a destination, and this replaces "localhost:9000". This is not perfect because i need to send a message to an actor just to find out to which instance I'm going to proxy the websocket, and only after can i proxy the request. A better solution would be where the router actor could do the job of the "websocketFlow".

The complete solution is to big to post here, but akka clustering and routing is well explained in its documentation http://doc.akka.io/docs/akka/current/java/cluster-usage.html