Akka流从外部世界获得无限流的当前值

时间:2017-12-06 21:39:25

标签: akka akka-stream

获取无限流的当前值的最佳方法是聚合值,按定义永远不会完成

Source.repeat(1)
  .scan(0)(_+_)
  .to(Sink.ignore)

我想从Akka HTTP查询当前的计数器值。我应该使用动态流吗? broadcastHub然后从Akka http订阅GET请求的无限流?

2 个答案:

答案 0 :(得分:1)

一种解决方案可能是使用演员来保持您需要的状态。 Sink.actorRef将现有的actor ref包装在接收器中,例如

class Keeper extends Actor {
  var i: Int = 0

  override def receive: Receive = {
    case n: Int ⇒ i = n
    case Keeper.Get ⇒ sender ! i
  }
}

object Keeper {
  case object Get
}

val actorRef = system.actorOf(Props(classOf[Keeper]))

val q = Source.repeat(1)
  .scan(0)(_+_)
  .runWith(Sink.actorRef(actorRef, PoisonPill))

val result = (actorRef ? Keeper.Get).mapTo[Int]

请注意,使用Sink.actorRef时不会保留背压。使用Sink.actorRefWithAck可以改善这一点。有关此内容的更多信息,请参阅docs

答案 1 :(得分:0)

一种可能是使用Sink.actorRefWithBackpressure

Imagina具有以下Actor来存储来自Stream的状态:

object StremState {
  case object Ack
  sealed trait Protocol                         extends Product with Serializable
  case object StreamInitialized                 extends Protocol
  case object StreamCompleted                   extends Protocol
  final case class WriteState[A](value: A)      extends Protocol
  final case class StreamFailure(ex: Throwable) extends Protocol
  final case object GetState                    extends Protocol
}

class StremState[A](implicit A: ClassTag[A]) extends Actor with ActorLogging {
  import StremState._

  var state: Option[A] = None

  def receive: Receive = {
    case StreamInitialized =>
      log.info("Stream initialized!")
      sender() ! Ack // ack to allow the stream to proceed sending more elements

    case StreamCompleted =>
      log.info("Stream completed!")

    case StreamFailure(ex) =>
      log.error(ex, "Stream failed!")

    case WriteState(A(value)) =>
      log.info("Received element: {}", value)
      state = Some(value)
      sender() ! Ack // ack to allow the stream to proceed sending more elements

    case GetState =>
      log.info("Fetching state: {}", state)
      sender() ! state

    case other =>
      log.warning("Unexpected message '{}'", other)

  }
}

然后可以在流接收器中使用此actor,如下所示:

    implicit val tm: Timeout           = Timeout(1.second)
    val stream: Source[Int, NotUsed]   = Source.repeat(1).scan(0)(_+_)

    val receiver = system.actorOf(Props(new StremState[Int]))
    val sink = Sink.actorRefWithBackpressure(
      receiver,
      onInitMessage = StremState.StreamInitialized,
      ackMessage = StremState.Ack,
      onCompleteMessage = StremState.StreamCompleted,
      onFailureMessage = (ex: Throwable) => StremState.StreamFailure(ex)
    )

    stream.runWith(sink)
    // Ask for Stream current state to the receiver Actor
    val futureState = receiver ? GetState