我想编写一个GraphStage,可以通过发送来自其他actor的消息暂停/取消暂停。
下面的代码显示了一个生成随机数的简单GraphStage
。当阶段实现后,GraphStageLogic
会向主管发送包含preStart()
的消息(在StageActor
内)。主管保持舞台的ActorRef
,因此可以用来控制舞台。
object RandomNumberSource {
case object Pause
case object UnPause
}
class RandomNumberSource(supervisor: ActorRef) extends GraphStage[SourceShape[Int]] {
val out: Outlet[Int] = Outlet("rnd.out")
override val shape: SourceShape[Int] = SourceShape(out)
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = {
new RandomNumberSourceLogic(shape)
}
private class RandomNumberSourceLogic(shape: Shape) extends GraphStageLogic(shape) with StageLogging {
lazy val self: StageActor = getStageActor(onMessage)
val numberGenerator: Random = Random
var isPaused: Boolean = true
override def preStart(): Unit = {
supervisor ! AssignStageActor(self.ref)
}
setHandler(out, new OutHandler {
override def onPull(): Unit = {
if (!isPaused) {
push(out, numberGenerator.nextInt())
Thread.sleep(1000)
}
}
})
private def onMessage(x: (ActorRef, Any)): Unit =
{
x._2 match {
case Pause =>
isPaused = true
log.info("Stream paused")
case UnPause =>
isPaused = false
getHandler(out).onPull()
log.info("Stream unpaused!")
case _ =>
}
}
}
}
这是一个非常简单的主管演员实现:
object Supervisor {
case class AssignStageActor(ref: ActorRef)
}
class Supervisor extends Actor with ActorLogging {
var stageActor: Option[ActorRef] = None
override def receive: Receive = {
case AssignStageActor(ref) =>
log.info("Stage assigned!")
stageActor = Some(ref)
ref ! Done
case Pause =>
log.info("Pause stream!")
stageActor match {
case Some(ref) => ref ! Pause
case _ =>
}
case UnPause =>
log.info("UnPause stream!")
stageActor match {
case Some(ref) => ref ! UnPause
case _ =>
}
}
}
我正在使用以下应用程序来运行流:
object Application extends App {
implicit val system = ActorSystem("my-actor-system")
implicit val materializer = ActorMaterializer()
val supervisor = system.actorOf(Props[Supervisor], "supervisor")
val sourceGraph: Graph[SourceShape[Int], NotUsed] = new RandomNumberSource(supervisor)
val randomNumberSource: Source[Int, NotUsed] = Source.fromGraph(sourceGraph)
randomNumberSource.take(100).runForeach(println)
println("Start stream by pressing any key")
StdIn.readLine()
supervisor ! UnPause
StdIn.readLine()
supervisor ! Pause
StdIn.readLine()
println("=== Terminating ===")
system.terminate()
}
当应用程序启动阶段ia处于“暂停”状态并且不产生任何数字时。当我按下一个键时,我的舞台开始发出数字。但我的问题是,在启动后发送到舞台的所有消息都将被忽略。我无法暂停舞台。
我有兴趣根据从演员那里收到的消息来改变舞台的行为,但是我找到的所有例子都将演员的消息传递给流。
是否有人猜到我的代码无效或者想知道如何构建这样的GraphStage
?
非常感谢!
答案 0 :(得分:1)
Akka Stream Contrib项目有一个Valve
阶段,它表示可以暂停和恢复流的值。来自此类的Scaladoc:
实现ValveSwitch的未来,它提供了一个方法翻转,用于停止或重新启动通过舞台的元素流。只要阀门关闭,它就会反压。
例如:
val (switchFut, seqSink) = Source(1 to 10)
.viaMat(new Valve(SwitchMode.Close))(Keep.right)
.toMat(Sink.seq)(Keep.both)
.run()
switchFut
是Future[ValveSwitch]
,由于开关最初关闭,阀门背压并且没有任何物质向下游排放。打开阀门:
switchFut.onComplete {
case Success(switch) =>
switch.flip(SwitchMode.Open) // Future[Boolean]
case _ =>
log.error("the valve failed")
}
更多示例位于ValveSpec
。