Je voudrais créer un Source
et plus tard des éléments Push dessus, comme dans:
val src = ... // create the Source here
// and then, do something like this
pushElement(x1, src)
pushElement(x2, src)
Quelle est la manière recommandée de procéder?
Merci!
Il y a trois façons d'y parvenir:
1. Post-matérialisation avec SourceQueue
Vous pouvez utiliser Source.queue
qui matérialise le Flow en SourceQueue
:
case class Weather(zipCode : String, temperature : Double, raining : Boolean)
val bufferSize = 100
//if the buffer fills up then this strategy drops the oldest elements
//upon the arrival of a new element.
val overflowStrategy = akka.stream.OverflowStrategy.dropHead
val queue = Source.queue(bufferSize, overflowStrategy)
.filter(!_.raining)
.to(Sink foreach println)
.run() // in order to "keep" the queue Materialized value instead of the Sink's
queue offer Weather("02139", 32.0, true)
2. Post-matérialisation avec acteur
Il y a une question et une réponse similaire ici , l'essentiel étant que vous matérialisiez le flux en tant que ActorRef et envoyiez des messages à cette référence:
val ref = Source.actorRef[Weather](Int.MaxValue, fail)
.filter(!_.raining)
.to(Sink foreach println )
.run() // in order to "keep" the ref Materialized value instead of the Sink's
ref ! Weather("02139", 32.0, true)
3. Pré-matérialisation avec acteur
De même, vous pouvez créer explicitement un acteur qui contient un tampon de messages, utiliser cet acteur pour créer une source, puis envoyer ces messages d'acteur comme décrit dans la réponse ici :
object WeatherForwarder {
def props : Props = Props[WeatherForwarder]
}
//see provided link for example definition
class WeatherForwarder extends Actor {...}
val actorRef = actorSystem actorOf WeatherForwarder.props
//note the stream has not been instatiated yet
actorRef ! Weather("02139", 32.0, true)
//stream already has 1 Weather value to process which is sitting in the
//ActorRef's internal buffer
val stream = Source(ActorPublisher[Weather](actorRef)).runWith{...}
Après avoir joué et cherché une bonne solution à cela, je suis tombé sur cette solution qui est propre, simple et fonctionne à la fois avant et après la matérialisation. https://stackoverflow.com/a/32553913/6791842
val (ref: ActorRef, publisher: Publisher[Int]) =
Source.actorRef[Int](bufferSize = 1000, OverflowStrategy.fail)
.toMat(Sink.asPublisher(true))(Keep.both).run()
ref ! 1 //before
val source = Source.fromPublisher(publisher)
ref ! 2 //before
Thread.sleep(1000)
ref ! 3 //before
source.runForeach(println)
ref ! 4 //after
Thread.sleep(1000)
ref ! 5 //after
Sortie:
1
2
3
4
5
Depuis Akka 2.5 Source
a une méthode preMaterialize
.
Selon le documentation , cela ressemble à la façon indiquée de faire ce que vous demandez:
Il existe des situations dans lesquelles vous avez besoin d'une valeur matérialisée
Source
avant que leSource
ne soit connecté au reste du graphique. Ceci est particulièrement utile dans le cas de sources "alimentées par la valeur matérialisée", commeSource.queue
,Source.actorRef
ouSource.maybe
.
Ci-dessous un exemple sur la façon dont ce serait avec un SourceQueue
. Les éléments sont poussés dans la file d'attente avant et après la matérialisation, ainsi que depuis Flow
:
import akka.actor.ActorSystem
import akka.stream.scaladsl._
import akka.stream.{ActorMaterializer, OverflowStrategy}
implicit val system = ActorSystem("QuickStart")
implicit val materializer = ActorMaterializer()
val sourceDecl = Source.queue[String](bufferSize = 2, OverflowStrategy.backpressure)
val (sourceMat, source) = sourceDecl.preMaterialize()
// Adding element before actual materialization
sourceMat.offer("pre materialization element")
val flow = Flow[String].map { e =>
if(!e.contains("new")) {
// Adding elements from within the flow
sourceMat.offer("new element generated inside the flow")
}
s"Processing $e"
}
// Actually materializing with `run`
source.via(flow).to(Sink.foreach(println)).run()
// Adding element after materialization
sourceMat.offer("post materialization element")
Sortie:
Processing pre materialization element
Processing post materialization element
Processing new element generated inside the flow
Processing new element generated inside the flow