3

I am using an API that accepts a single AKKA Sink and fills it with data:

def fillSink(sink:Sink[String, _])

Is there a way, without delving into the depths of akka, to handle the output with two sinks instead of one?

For example

val mySink1:Sink = ...
val mySink2:Sink = ...
//something
fillSink( bothSinks )

If I had access to the Flow used by the fillSink method I could use flow.alsoTo(mySink1).to(mySink2) but the flow is not exposed.

The only workaround at the moment is to pass a single Sink which handles the strings and passes it on to two StringBuilders to replace mySink1/mySink2, but it feels like that defeats the point of AKKA. Without spending a couple days learning AKKA, I can't tell if there is a way to split output from sinks.

Thanks!

Jethro
  • 3,029
  • 3
  • 27
  • 56
  • 2
    You have access to the flow ... `Flow[T].alsoTo(mySink1).to(mySink2)` – cchantep Sep 26 '19 at 15:47
  • 1
    You should check https://stackoverflow.com/questions/38438983/split-akka-stream-source-into-two – Aleksey Isachenkov Sep 26 '19 at 16:38
  • There is an answer with broadcast usage. It's a bit ugly but simple. – Aleksey Isachenkov Sep 26 '19 at 16:39
  • Thanks @cchantep, `Flow[String].alsoTo(mySink1).to(mySink2)` on it's own seems to do nothing, and i've got nothing I can do with the `Flow[String, String,NotUsed]` instance i'm given? Thanks @aleksey-isachenkov! I'm trying to adapt that to my use case (https://github.com/doriordan/skuber/blob/d0a950c00b5a35484692d02f9b96933ebae90700/client/src/main/scala/skuber/api/client/KubernetesClient.scala#L343) using cessationoftime's answer, but not sure what i'm going to do with the `val flow`. I don't yet see how these approaches help when I only have a reference to the Sink. – Jethro Sep 26 '19 at 19:03

1 Answers1

4

The combine Sink operator, which combines two or more Sinks using a provided Int => Graph[UniformFanOutShape[T, U], NotUsed]] function, might be what you're seeking:

def combine[T, U](first: Sink[U, _], second: Sink[U, _], rest: Sink[U, _]*)(strategy: Int => Graph[UniformFanOutShape[T, U], NotUsed]): Sink[T, NotUsed]

A trivialized example:

val doubleSink = Sink.foreach[Int](i => println(s"Doubler: ${i*2}"))
val tripleSink = Sink.foreach[Int](i => println(s" Triper: ${i*3}"))

val combinedSink = Sink.combine(doubleSink, tripleSink)(Broadcast[Int](_))

Source(List(1, 2, 3)).runWith(combinedSink)

// Doubler: 2
//  Triper: 3
// Doubler: 4
//  Triper: 6
// Doubler: 6
//  Triper: 9
Leo C
  • 22,006
  • 3
  • 26
  • 39