The docs state:
Join this Flow to another Flow, by cross connecting the inputs and outputs, creating a RunnableGraph
Here is a good example from akka.http.scaladsl
that can help explain why this is useful:
/**
* Represents one accepted incoming HTTP connection.
*/
final case class IncomingConnection(
localAddress: InetSocketAddress,
remoteAddress: InetSocketAddress,
flow: Flow[HttpResponse, HttpRequest, NotUsed]) {
/**
* Handles the connection with the given flow, which is materialized exactly once
* and the respective materialization result returned.
*/
def handleWith[Mat](handler: Flow[HttpRequest, HttpResponse, Mat])(implicit fm: Materializer): Mat =
flow.joinMat(handler)(Keep.right).run()
As you may know a handler
for an Akka http flow always flow from HttpRequest
to HttpResponse
, but as you can see an IncomingConnection.flow
flows from HttpResponse
to a HttpRequest
. In other words, it's the user's responsibility to create a response out of a request and Akka Http's responsibility to send that response and produce another request. This does indeed make a closed loop when it involves another Flow, therefore the join
method creates a RunnableGraph
.
To understand how the connection is handled you should learn a little bit more about BidiFlow
. The result of a BidiFlow#join
is another flow, because a BidiFlow has two inputs and two outputs. Here is a link to an excellent explanation with examples.