代码之家  ›  专栏  ›  技术社区  ›  zella

如何取消游戏框架内的Akka流

  •  0
  • zella  · 技术社区  · 8 年前

    我有一个流,它应该由HTTP API控制(开始、停止,只有一个实例)。应将响应流式传输到客户端。以下是播放框架控制器的代码:

      class Processor{
    
        def job(): Source[Int, NotUsed] ={
          stop()
          Source(Stream.from(1)).delay(1.second, DelayOverflowStrategy.backpressure)
        }
    
        def stop(): Unit ={
          //TODO
        }
      }
    
      class MyController(process: Processor) {
    
        def startJob = Action {
          val source = process.job()
          Ok.chunked(source)
        }
    
        def cancell = Action {
          process.cancel()
          Ok("canceled")
        }
      }
    

    我需要取消工作的能力。当客户端关闭连接时,作业不应该取消-它就像日志输出一样。我读到关于 KillSwitches 但不要低估如何使用它与游戏控制器,这接受 Source . 有什么帮助吗?

    我想我需要一些不同于工作来源的输出来源。

    1 回复  |  直到 8 年前
        1
  •  0
  •   zella    8 年前

    我用 Monix Observable . 通过操作,我可以运行、取消和连接到正在运行的流。总之,我对Akka流解决方案的教育目的感兴趣。这里是monix解决方案:

    class StreamService(implicit ec: Scheduler) {
    
      private val runningStream: AtomicAny[Option[RunningStream]] = AtomicAny(None)
    
      def run(): Option[Source[ByteString, NotUsed]] =
        runningStream.get match {
          case None =>
            val observable = Observable
              .interval(1.seconds)
              .map(_.toString)
              .doOnTerminate(cb => runningStream.set(None))
              .doOnSubscriptionCancel(() => runningStream.set(None))
              .publish
    
            val cancelable_ = observable.connect()
    
            this.runningStream.set(Some(RunningStream(cancelable_, observable)))
            connect()
          case _ => None
        }
    
      def connect(): Option[Source[ByteString, NotUsed]] =
        runningStream.get
          .map(rs => rs.observable.toReactivePublisher)
          .map(publisher => Source.fromPublisher(publisher).map(ByteString(_)))
    
      def cancel(): Unit =
        runningStream.get.foreach(_.cancelable.cancel())
    
    }
    
    object StreamService {
      case class RunningStream(cancelable: Cancelable, observable: ConnectableObservable[String])
    }
    
    
    class SomeController @Inject()(streamService: StreamService, cc: ControllerComponents)
      extends AbstractController(cc) {
    
      def run() = Action {
        val source = streamService.run().getOrElse(throw new RuntimeException("Stream already running"))
        Ok.chunked(source)
      }
    
      def connect() = Action {
        val source = streamService.connect().getOrElse(throw new RuntimeException("Stream not running"))
        Ok.chunked(source)
      }
    
      def cancel() = Action {
        streamService.cancel()
        Ok("ok")
      }
    }