Search code examples
scalaakkaakka-http

Shut down Akka HTTP app


I have a running Akka HTTP application and I want to shut it down.

Pressing Ctrl + C in SBT does not work for me (my shell is currently Git Bash for Windows).

What's the recommended way of shutting down an Akka app gracefully?


Solution

  • Taking inspiration from this thread, I added a route to my application that shuts down the application:

    def shutdownRoute: Route = path("shutdown") {
      Http().shutdownAllConnectionPools() andThen { case _ => system.terminate() }
      complete("Shutting down app")
    }
    

    where system is the app's ActorSystem.

    Given this route, I can now shut down my application with

    curl http://localhost:5000/shutdown
    

    Edit:

    Being able to shut down a server remotely is not a good idea for production code. In the comments, Henrik pointed to a different way that shuts down the server by hitting Enter in the SBT console:

    StdIn.readLine()
    // Unbind from the port and shut down when done
    bindingFuture
      .flatMap(_.unbind())
      .onComplete(_ => system.terminate())
    

    For context, I put the above code at the end of server initialization:

    // Gets the host and a port from the configuration
    val host = system.settings.config.getString("http.host")
    val port = system.settings.config.getInt("http.port")
    
    implicit val materializer = ActorMaterializer()
    
    // bindAndHandle requires an implicit ExecutionContext
    implicit val ec = system.dispatcher
    
    import akka.http.scaladsl.server.Directives._
    val route = path("hi") {
      complete("How's it going?")
    }
    
    // Starts the HTTP server
    val bindingFuture: Future[ServerBinding] =
      Http().bindAndHandle(route, host, port)
    
    val log = Logging(system.eventStream, "my-application")
    
    bindingFuture.onComplete {
      case Success(serverBinding) =>
        log.info(s"Server bound to ${serverBinding.localAddress}")
    
      case Failure(ex) =>
        log.error(ex, "Failed to bind to {}:{}!", host, port)
        system.terminate()
    }
    
    log.info("Press enter key to stop...")
    // Let the application run until we press the enter key
    StdIn.readLine()
    // Unbind from the port and shut down when done
    bindingFuture
      .flatMap(_.unbind())
      .onComplete(_ => system.terminate())