播放框架Scala:使用scala akka流创建无限源,并使服务器上的事件发送连接在服务器上保持打开状态

时间:2018-10-01 07:15:18

标签: scala akka-stream server-sent-events playframework-2.6

对于以下用例,我们要求实现服务器发送的事件

  1. 在服务器上进行一些处理后,将通知发送到UI。此处理基于某些逻辑
  2. 从RabbitMQ读取消息后向其发送通知,然后对其执行一些操作。

我们在Scala(2.11 / 2.12)和Play框架(2.6.x)中使用了技术。 库: akka.stream.scaladsl.Source

我们从下面的示例https://github.com/playframework/play-scala-streaming-example开始我们的概念验证,然后通过创建不同的来源进行扩展。 我们尝试使用Source.apply,soure.single创建源。

但是一旦将源中的所有元素都推送到UI,我的事件流就会关闭。但是我不希望事件流关闭。另外,我也不想使用某些计时器(Source.tick)或Source.repeat。

创建我的源代码后,集合让我们说了一些x元素,然后服务又添加了4个元素。但是在x个元素之后,事件流关闭,然后再次重新打开。

有什么方法可以使我的事件流变为无限,并且仅在我的会话注销或我们可以显式关闭它的情况下才会关闭它。

// KeepAlive的代码(如注释中所述)

   object NotficationUtil {

      var userNotificationMap = Map[Integer, Queue[String]]()

      def addUserNotification(userId: Integer, message: String) = {
        var queue = userNotificationMap.getOrElse(userId, Queue[String]())
        queue += message
        userNotificationMap.put(userId, queue)

      }

      def pushNotification(userId: Integer): Source[JsValue, _] = {
        var queue = userNotificationMap.getOrElse(userId, Queue[String]())
         Source.single(Json.toJson(queue.dequeueAll { x => true }))
      }
    }
    @Singleton
    class EventSourceController @Inject() (cc: ControllerComponents) extends AbstractController(cc) with FlowFactory{

      def pushNotifications(user_id:Integer) = Action {
      val stream = NotficationUtil.pushNotification(user_id)
       Ok.chunked(stream.keepAlive(50.second, ()=>Json.obj("data"->"heartbeat")) via EventSource.flow).as(ContentTypes.EVENT_STREAM)
     }

}

1 个答案:

答案 0 :(得分:0)

使用以下代码创建actorref和发布者

val (ref, sourcePublisher)= Source.actorRef[T](Int.MaxValue, OverflowStrategy.fail).toMat(Sink.asPublisher(true))(Keep.both).run()

并从此发布者创建您的来源

val testsource = Source
      .fromPublisher[T](sourcePublisher)

然后将您的听众注册为

Ok.chunked(
        testsource.keepAlive(
          50.seconds,
          () => Json.obj("data"->"heartbeat")) via EventSource.flow)
      .as(ContentTypes.EVENT_STREAM)
      .withHeaders("X-Accel-Buffering" -> "no", "Cache-Control" -> "no-cache")

将json数据发送给ref actor,数据将作为事件流通过此源流到前端。 希望对您有所帮助。