How to add elements to Source dynamically?

前端 未结 3 1737
礼貌的吻别
礼貌的吻别 2020-12-14 07:50

I have example code to generate an unbound source and working with it:

object Main {

 def main(args : Array[String]): Unit = {

  implicit val system         


        
相关标签:
3条回答
  • 2020-12-14 08:25

    With Akka Streams 2 you can use a sourceQueue : How to create a Source that can receive elements later via a method call?

    0 讨论(0)
  • 2020-12-14 08:26

    One way to have a non-finite source is to use a special kind of actor as the source, one that mixes in the ActorPublisher trait. If you create one of those kinds of actors, and then wrap with a call to ActorPublisher.apply, you end up with a Reactive Streams Publisher instance and with that, you can use an apply from Source to generate a Source from it. After that, you just need to make sure your ActorPublisher class properly handles the Reactive Streams protocol for sending elements downstream and you are good to go. A very trivial example is as follows:

    import akka.actor._
    import akka.stream.actor._
    import akka.stream.ActorFlowMaterializer
    import akka.stream.scaladsl._
    
    object DynamicSourceExample extends App{
    
      implicit val system = ActorSystem("test")
      implicit val materializer = ActorFlowMaterializer()
    
      val actorRef = system.actorOf(Props[ActorBasedSource])
      val pub = ActorPublisher[Int](actorRef)
    
      Source(pub).
        map(_ * 2).
        runWith(Sink.foreach(println))
    
      for(i <- 1 until 20){
        actorRef ! i.toString
        Thread.sleep(1000)
      }
    
    }
    
    class ActorBasedSource extends Actor with ActorPublisher[Int]{
      import ActorPublisherMessage._
      var items:List[Int] = List.empty
    
      def receive = {
        case s:String =>
          if (totalDemand == 0) 
            items = items :+ s.toInt
          else
            onNext(s.toInt)    
    
        case Request(demand) =>  
          if (demand > items.size){
            items foreach (onNext)
            items = List.empty
          }
          else{
            val (send, keep) = items.splitAt(demand.toInt)
            items = keep
            send foreach (onNext)
          }
    
    
        case other =>
          println(s"got other $other")
      }
    
    
    }
    
    0 讨论(0)
  • 2020-12-14 08:45

    As I mention in this answer, the SourceQueue is the way to go, and since Akka 2.5 there is a handy method preMaterialize which eliminates the need to create a composite source first.

    I give an example in my other answer.

    0 讨论(0)
提交回复
热议问题