完整请求,包含流程中的最新项目

时间:2018-06-16 12:56:02

标签: scala akka akka-stream akka-http reactive-streams

我希望使用流程中的最新可用项目完成camera.fov请求。此流程特别聚合由actor生成并已由WebSocket单独使用的事件。

让我们说事件可以表示如下:

GET

我要做的第一件事就是创建一个final case class Event(id: String, value: Double) ,其中演员将推送事件和集线器,以便不同的客户可以独立接收这些事件:

SourceQueue

然后我能够创建一个actor,它可以将事件推送到val (queue, hub) = Source.queue[Event](256, OverflowStrategy.dropHead). toMat(BroadcastHub.sink(bufferSize = 256))(Keep.both).run() 并将queue传递给通过WebSocket服务事件的服务:

hub

这种方法很好,同时也有多个消费者。

我接下来要做的是使用服务来消费extractUpgradeToWebSocket { upgrade => complete(upgrade.handleMessagesWithSinkSource( inSink = Sink.ignore, outSource = hub.map(in => TextMessage(fmt.write(in).toString())) )) } 中的事件,并生成每个ID的最新事件列表,通过hub端点提供。

我尝试了几种方法来解决这个问题。我尝试的两种方法是:

  • 运行更新私有变量的流程
  • 完成了一个返回GET元素
  • 的接收器

运行更新私有变量

的流程

实际上,这是我尝试的最后一种方法。我注意到的奇怪(或者是它?)实际上没有记录任何内容(不应该记录通过last组合器的东西吗?)。

使用这种方法的结果是log总是latest,因此响应总是为空。

null

我也尝试过类似的方法,使用"框"演员并将聚合管道传递给它,但效果是一样的。

使用接收器返回final class Service(hub: Source[Event, NotUsed])(implicit s: ActorSystem, m: ActorMaterializer, t: Timeout) extends Directives with JsonSupport { implicit private val executor = system.dispatcher @volatile private[this] var latest: List[Event] = _ hub. log("hub", identity). groupBy(Int.MaxValue, { case Event(id, _) => id }). map { case event @ Event(id, _) => Map(id -> event) }. reduce(_ ++ _). mergeSubstreams. map(_.values.toList). toMat(Sink.foreach(latest = _))(Keep.none).run() val definition = get { complete(Option(latest)) } } 元素

这是我尝试采取的第一种方法。结果是响应挂起,直到达到超时并且Akka HTTP向浏览器返回500。

last

1 个答案:

答案 0 :(得分:1)

ActorRef作为接收器

您可以创建一个Actor,使Map id的{​​{1}}保持Event

import scala.collection.immutable

object QueryMap

class MapKeeperActor() extends Actor {

  var internalMap = immutable.Map.empty[String, Event]

  override def receive = {
    case e : Event    => internalMap = internalMap + (e.id -> e)
    case _ : QueryMap => sender ! internalMap
  }
}

然后可以在Sink中使用此引用,该BroadcastHub将附加到object OnCompleteMessage val system : ActorSystem = ??? val mapKeeperRef = system.actorOf(Props[MapKeeperActor]) val mapKeeperSink : Sink[Event, _] = Sink.actorRef[Event](mapKeeperRef, OnCompleteMessage)

Route

在路线中查询演员

我们现在可以创建一个Map,它将使用指令查询地图管理员。但是,您必须决定如何将ResponseEntity序列化为HttpResponse的{​​{1}}:

val serializeMap : Map[String, Event] => ResponseEntity = ???

val route = 
  get {
    onComplete( (mapKeeperRef ? QueryMap).mapTo[Map[String, Event]]) {
      case Success(map) => complete(HttpResponse(entity=serializeMap(map))
      case Failure(ex)  => complete((InternalServerError, s"An error occurred: ${ex.getMessage}"))
    }
  }