Почему это немедленно прекращается? - PullRequest
1 голос
/ 24 мая 2019

У меня есть следующий код, и я хотел бы понять, почему он немедленно останавливается, когда я его выполняю:

    import akka.actor.ActorSystem
    import akka.http.scaladsl.Http
    import akka.http.scaladsl.model._
    import akka.http.scaladsl.server.Directives._
    import akka.stream.ActorMaterializer
    import scala.io.StdIn

    object WebServer {
      def main(args: Array[String]) {

        implicit val system = ActorSystem("my-system")
        implicit val materializer = ActorMaterializer()
        // needed for the future flatMap/onComplete in the end
        implicit val executionContext = system.dispatcher

        val route =
          path("hello") {
            get {
              complete(HttpEntity(ContentTypes.`text/html(UTF-8)`, "<h1>Say hello to akka-http</h1>"))
            }
          }

        val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
        bindingFuture
          .flatMap(_.unbind()) // trigger unbinding from the port
          .onComplete(_ => system.terminate()) // and shutdown when done
      }
    }

Как видите, это простое веб-приложение, и оно не должно останавливаться назапустить.
Но когда я удаляю следующий код:

bindingFuture
  .flatMap(_.unbind()) // trigger unbinding from the port
  .onComplete(_ => system.terminate()) // and shutdown when done 

Тогда он будет работать вечно, пока я не завершу его.
Вопрос в том, почему без

bindingFuture
  .flatMap(_.unbind()) // trigger unbinding from the port
  .onComplete(_ => system.terminate()) // and shutdown when done 

приложение не собирается прекращать работу?

1 Ответ

7 голосов
/ 24 мая 2019

Ваш bindingFuture завершается в обоих случаях. Если вы держите

bindingFuture
  .flatMap(_.unbind()) // trigger unbinding from the port
  .onComplete(_ => system.terminate()) // and shutdown when done 

Затем unbind и terminate запускаются, как только сервер прослушивает, что приводит к немедленному завершению работы вашей программы.

Если вы пропустите этот код, то ваша программа продолжит работать, пока все ее потоки не будут завершены. Поскольку система акторов выполняет потоки в фоновом режиме, и вы никогда не завершаете ее, этого никогда не произойдет, и вам придется убить вашу программу, чтобы остановить ее.

Одним из способов постепенного отключения при любом нажатии клавиши является использование этого (взято из официальной документации )

val bindingFuture = Http().bindAndHandle(route, "localhost", 8080)
println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
  .flatMap(_.unbind()) // trigger unbinding from the port
  .onComplete(_ => system.terminate()) // and shutdown when done

В этом случае StdIn.readLine() будет блокировать основной поток до тех пор, пока не будет нажата клавиша, после чего система субъекта и http-сервер будут закрыты.

Если вы хотите дождаться пользовательского «события», а не нажатия клавиши, вы можете просто подождать на пользовательском Future, например так:

// Just build a Future that will get completed when you want to shutdown
// This can be done manually using a `Promise[Unit]`, but you might also be using 
// a library that will give you a Future to wait on.
val myFuture: Future[Unit] = ??? 
myFuture.flatMap(_ => bindingFuture)
    .flatMap(_.unbind())
    .onComplete(_ => system.terminate())
...