0

I have a WebSocket server in a Play app, and I want to move it to an akka-http service. I'm currently using ActorFlow.actorRef, which is a part of Play that doesn't exist in Akka.

When the WebSocket is accepted, I subscribe to a RabbitMQ queue, and forward each message to the WebSocket. When I receive a message from the WebSocket, I handle some locally and forward others on to a RabbitMQ exchange.

How would I do the same using akka-http? I can create a sink using Sink.actorRef and handle inbound messages there, but what about the source?

I can create a source with Source.actorRef, but how do I get access to the actor to send messages to when it's materialized? Is there a different kind of source I should use to send messages to from the foreach of my RabbitMQ subscription?

Once I have those, it looks like I can return the required flow using Flow.fromSinkAndSource.

Isvara
  • 3,403
  • 1
  • 28
  • 42
  • Can you show what you've done so far so we can get more context? If you're looking for how to obtain materialized value, which is the actorRef in this case, [mapMaterialized](http://doc.akka.io/api/akka/current/index.html#akka.stream.scaladsl.Source@mapMaterializedValue[Mat2](f:Mat=>Mat2):Source.this.ReprMat[Out,Mat2]) might be what you're looking for – Qingwei Sep 21 '16 at 01:14
  • @Qingwei I've been through a couple of different iterations, but this is what I have at the moment (using code taken from Play's `ActorFlow.actorRef`). It closes the connection as soon as it's opened, though. https://gist.github.com/danellis/643e858d830dbea58bd84e265fb64110 – Isvara Sep 21 '16 at 03:43

1 Answers1

0

I'll paraphrase your requirements

You have a websocket end point which needs to

  1. Process some request locally and send response back to client
  2. Forward some request to RabbitMQ
  3. Subscribe to rabbitMQ, and forward message from rabbitMQ to websocket client.

My suggestion is that avoid actor unless necessary, actor is powerful, but I find stream easier to read and reason about when it fits the model

Below is how you pipe Source and Sink together without actor

def wshandler: Flow[Message, Message, _] = {
    val rabbit = new Rabbit()
    val src =
      Source
        .actorRef(100, OverflowStrategy.dropBuffer)
        .mapMaterializedValue(ref => {
          rabbit
            .subscribe[String]("updates", queueName, topics) { 
              (body, topic) =>
                log.debug("Received from rabbit")

                // here you forward everything from rabbitmq to    
                // client using materialized actorRef
                ref ! TextMessage(body)
            }
        })

    // you need to implement your own pattern matching logic to differentiate between request to process 
    // locally and request to route to rabbitMQ
    val sink = Sink.foreach[Message](m => m match {
      case localReq => // your request response processing logic

      case rabbitMq => // publish to rabbitMQ
    })

    Flow.fromSinkAndSource(sink, src)
  }

This snippet does not implement anything of the gist you showed, hope it solve your problem

Qingwei
  • 510
  • 6
  • 13
  • The problem with that is that there's no actor to stash solicitations until the subscription has completed, as in my gist. – Isvara Sep 21 '16 at 21:28
  • Sorry, I should've confirm with you what's the issue with your gist then? it does not compile? of it closes connection once it's opened? – Qingwei Sep 22 '16 at 02:53
  • Yeah, as I said, it closes the connection as soon as it's opened. I've absolutely no idea why. – Isvara Sep 22 '16 at 02:55
  • So I'm trying this out, but the function I pass to `mapMaterializedValue` never actually gets called. When is that supposed to happen? (To be clear, the source is being created.) – Isvara Sep 22 '16 at 23:55
  • Source creation is separated from source materialization, and materialization supposed to handle by akka-http, what happen when you try to connect to the websocket endpoint? – Qingwei Sep 23 '16 at 11:10
  • Right, the source is created, but it apparently never gets materialized. Akka just closes the socket. So something else must be wrong inside the handler, but it's not logging anything. It does return a 101 response, though. – Isvara Sep 23 '16 at 16:25
  • @Derecho without the ability to run the code, I doubt I have the ability to help, sorry =( – Qingwei Sep 24 '16 at 06:26