0

I'm trying to use akka-streams and akka-http in order to solve the following problem:

  • we have 2 http clients (A and B) sending requests to 1 http server (C). Both side use akka-http to communicate.
  • requests from A have higher priority compared to B, but both requests should be processes equally. So C should first process requests from A, requests from B are of second priority
  • of course we would like to have back-pressure on each end enabled

I come up with the following code in order to get incoming connections merged to one output:

val g = RunnableGraph.fromGraph(FlowGraph.create() { implicit b: FlowGraph.Builder[Unit] =>
    import FlowGraph.Implicits._

    val merge = b.add(MergePreferred[IncomingConnection](1))

    val inA: Source[IncomingConnection, Future[ServerBinding]] = Http().bind(interface = "localhost", port = 8200)
    val inB: Source[IncomingConnection, Future[ServerBinding]] = Http().bind(interface = "localhost", port = 8201)

    inA ~> merge.preferred
    inB ~> merge.in(0)
           merge.out ~> Sink.foreach(println)

    ClosedShape
}).run()

So, I have a Source with IncomingConnection inctances from A and B.

Now I want to process them somehow, produce responses and send responses to corresponding connections.

Maybe there are better ways to archive all these things but I could not find any example solving such problem in docs or questions from other people.

Also I guess the problem is quite common.

Thanks in advance for your help.

d-n-ust
  • 122
  • 1
  • 9

1 Answers1

1

The way IncomingConnection objects are used to process requests and return responses is with the handleXXX methods. Examples based on the documentation and the api:

Synchronous Function

//this processor contains your logic for converting a request into a response
def requestProcessor(httpRequest : HttpRequest) : HttpResponse = ???

val connectionSink = Sink.foreach[IncomingConnection] { conn =>
  conn.handleWithSyncHandler(requestProcessor)
}

This connectionSink can then be used in your graph construct:

inA ~> merge.preferred
inB ~> merge.in(0)
       merge.out ~> connectionSink

Asynchronous Function

Similarly, if your processor is asynchronous:

val asyncReqProcessor(httpRequest : HttpRequest) : Future[HttpResponse] = ???

val connectionSink = 
  Sink.foreach[IncomingConnection](_ handleWithAsyncHandler asyncProcessor)

Flow

And finally, you can also use a Flow (my preferred method):

val flowReqProcessor : Flow[HttpRequest, HttpResponse,_] = ???

val connectionSink = 
  Sink.foreach[IncomingConnection](_ handleWith flowReqProcessor )

One of my favorite features about Flows is that you can re-use them over & over in different Streams. Therefore, flowReqProcessor can be a val instead of a def.

Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
  • Thanks! Just what I needed. Would be great to update documentation with more examples on handling connections... – d-n-ust Dec 16 '15 at 13:10
  • @d-n-ust You are welcome. I agree the docs are a bit lacking at times. akka-streams was promoted out of "experimental" just this past July so it is still young. In the past few months I think I've seen the reference docs double in size (slowly but surely). Happy hacking! – Ramón J Romero y Vigil Dec 16 '15 at 13:14
  • The solution actually does not solve my problem - I need to prioritize requests, not connections (started another thread: http://stackoverflow.com/questions/34315419/how-to-convert-sourceincomingconnection-to-sourcehttprequest) – d-n-ust Dec 16 '15 at 16:40