1

I'm looking for akka.stream.scaladsl.Source construction method that will allow me to simply emit next value from different place of code (e.g. watching on system events).

  • I need somethig similar to Promise. Promise emits single value to Future. I need to emit multiple values to Source.
  • like monix.reactive.subjects.BehaviorSubject.onNext(_)
  • I don't care about backpressure too much.

currently I've implemented this using monix & akka-streams (code below) but I expect that there should be akka-streams only sollution:

import akka.stream.scaladsl.{Flow, Sink, Source}
import monix.reactive.subjects.BehaviorSubject
import monix.execution.Scheduler.Implicits.global

val bs = BehaviorSubject("") //monix subject is sink and source at the same time

//this is how it is currently implemented
def createSource() = { 
    val s1 = Source.fromPublisher(bs.toReactivePublisher) //here we create source from subject
    Flow.fromSinkAndSourceCoupled[String, String](Sink.ignore, s1)
}

//somewhere else in code... some event happened
//this is how it works in monix.
val res:Future[Ack] = bs.onNext("Event #1471 just happened!") //here we emit value
Scalway
  • 1,633
  • 10
  • 18
  • 1
    Maybe this topic would be useful: https://stackoverflow.com/questions/36397424/how-to-use-an-akka-streams-sourcequeue-with-playframework – Marcus Linke Mar 06 '20 at 09:23
  • Yes... this was helpful. The `Source.queue(...)` solves a problem. Thanks a lot. – Scalway Mar 06 '20 at 13:09

4 Answers4

2

Perhaps you are looking for Actor Source

An example from the docs:

import akka.actor.typed.ActorRef
import akka.stream.OverflowStrategy
import akka.stream.scaladsl.{ Sink, Source }
import akka.stream.typed.scaladsl.ActorSource

trait Protocol
case class Message(msg: String) extends Protocol
case object Complete extends Protocol
case class Fail(ex: Exception) extends Protocol

val source: Source[Protocol, ActorRef[Protocol]] = ActorSource.actorRef[Protocol](completionMatcher = {
  case Complete =>
}, failureMatcher = {
  case Fail(ex) => ex
}, bufferSize = 8, overflowStrategy = OverflowStrategy.fail)

val ref = source
  .collect {
    case Message(msg) => msg
  }
  .to(Sink.foreach(println))
  .run()

ref ! Message("msg1")

This way you would be able to send messages to actor via actor system, and these messages will be emitted from the ActorSource down the stream.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64
0

Source abstraction, as name says, provide API to work with data source. Instead, you need to take a look at abstraction which consumes data - Sink. And Sink.foreach operation is what you are looking for, most likely: https://doc.akka.io/docs/akka/current/stream/operators/Sink/foreach.html

In you case, the code would look something like:

import akka.stream.scaladsl.{Sink, Source}

val s1 = Source.// your WS akka stream source
s1.runWith(Sink.foreach(write))

Hope this helps!

Ivan Kurchenko
  • 4,043
  • 1
  • 11
  • 28
  • Not what i wanted. I really need to create Source... not Sink. I just need to create it in such way that items could be emitted from other parts of code freely. Something like Promise and Future. – Scalway Mar 05 '20 at 13:32
0

I think what you are looking for is sink.foreach.it invoke a given procedure for each element received.I think code will look like:

s1.runWith(Sink.foreach(write))

Essentially, what is being done is that for stream a source, sink tries to write every element of that stream.

EDIT

I think you are looking for maybe. It creates a source that emits once the materialized Promise is completed with a value.Check out this documentation

EDIT

futureSource may also work.It streams the elements of the given future source once it successfully completes it.

Let me know if it helps!!

Anand Sai
  • 1,566
  • 7
  • 11
0

https://doc.akka.io/docs/akka/current/stream/operators/Source/fromIterator.html or https://doc.akka.io/docs/akka/current/stream/operators/Source/fromPublisher.html is what you need, depending on where does your Source consume data from.

yiksanchan
  • 1,890
  • 1
  • 13
  • 37