升级sbt至1.5.8以上版本后AkkaHttpServer启动即停止问题
问题:sbt升级至1.6.X及以上版本后,Akka HTTP服务器启动即停止
现象
原本稳定运行的Akka HTTP应用,在将sbt从1.5.8升级到1.6.X、1.7.X、1.8.X或1.9.0版本后,出现以下问题:
- 在sbt交互模式执行
run命令,命令会直接退出回到sbt提示符 - 执行
sbt run命令,sbt会直接退出,服务器无法保持运行
sbt 1.6+版本运行日志
sbt:project> run [info] running com.------.Application 12:47:27.125 [Server-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started SLF4J: A number (1) of logging calls during the initialization phase have been intercepted and are SLF4J: now being replayed. These are subject to the filtering rules of the underlying logging system. SLF4J: See also https://www.slf4j.org/codes.html#replay 12:47:27.842 [Server-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started [success] Total time: 3 s, completed 22 Jun 2023, 12:47:28 12:47:28.241 [Server-akka.actor.default-dispatcher-3] INFO akka.actor.typed.ActorSystem - Server online at http://0.0.0.0:8080/ for docker or http://127.0.0.1:8080 sbt:project>
sbt 1.5.8版本运行日志
sbt:project> run [info] running com.-------.Application 13:13:13.093 [Server-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started SLF4J: A number (1) of logging calls during the initialization phase have been intercepted and are SLF4J: now being replayed. These are subject to the filtering rules of the underlying logging system. SLF4J: See also https://www.slf4j.org/codes.html#replay 13:13:13.481 [Server-akka.actor.default-dispatcher-3] INFO akka.event.slf4j.Slf4jLogger - Slf4jLogger started 13:13:13.730 [Server-akka.actor.default-dispatcher-3] INFO akka.actor.typed.ActorSystem - Server online at http://0.0.0.0:8080/ for docker or http://127.0.0.1:8080
使用的依赖版本:
val AkkaVersion = "2.6.20" //apache 2.0 license val AkkaHttpVersion = "10.2.10" //apache 2.0 license
原因分析
sbt 1.6.0及以上版本对run任务的默认行为做了调整:
- 未启用fork模式时,sbt会在主线程执行完
Apptrait的代码后立即标记任务完成并退出,不会等待Akka后台的ActorSystem线程。 - 从日志可见,sbt先输出
[success],之后Akka才输出服务器上线日志,说明主线程已结束,sbt直接终止了整个进程。 - 而sbt 1.5.8版本中,主线程会被Akka的线程持有,保持进程持续运行。
解决方案
方案1:修改sbt的fork配置
在build.sbt中添加以下配置,启用fork模式并保持输入连接,让sbt等待子进程结束:
run / fork := true run / connectInput := true
启用fork后,Akka服务器会在独立子进程中运行,sbt会一直等待子进程终止,直到你手动停止服务器。
方案2:修改应用代码,让主线程等待ActorSystem终止
在应用入口类中添加代码,让主线程阻塞等待ActorSystem终止,避免主线程提前结束:
import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import scala.concurrent.Await import scala.concurrent.duration.Duration object Application extends App { // 初始化ActorSystem val system = ActorSystem(Behaviors.setup { context => // 这里添加Akka HTTP服务器的启动逻辑 // ... Behaviors.empty }, "Server") // 阻塞主线程,等待ActorSystem终止 Await.result(system.whenTerminated, Duration.Inf) }
也可以使用非阻塞方式监听终止事件:
import akka.actor.typed.ActorSystem import akka.actor.typed.scaladsl.Behaviors import scala.concurrent.ExecutionContext.Implicits.global object Application extends App { val system = ActorSystem(Behaviors.setup { context => // 启动Akka HTTP服务器逻辑 // ... Behaviors.empty }, "Server") // 监听ActorSystem终止事件,终止时退出JVM system.whenTerminated.onComplete(_ => System.exit(0)) }
这两种方案都能让sbt的run任务保持运行,直到服务器被手动停止。
内容的提问来源于stack exchange,提问作者Roman Kazanovskyi
相关产品推荐
相关产品推荐

