我有基于 spray.io 的webservice,它作为独立jar运行(我使用sbt assembly
然后只使用java -jar myws.jar
)。它与喷涂示例中的靴带非常相似,如下所示:
/** Bootstrap */
object Boot extends App {
// we need an ActorSystem to host our application in
implicit val system = ActorSystem("my-system")
// create and start our service actor
val service = system.actorOf(Props[MyServiceActor], "my-ws-service")
implicit val timeout = Timeout(10.seconds)
CLIOptionsParser.parse(args, CLIOptionsConfig()) map { config =>
// start a new HTTP server
IO(Http) ? Http.Bind(service, interface = config.interface, port = config.port)
}
}
现在,我只需使用java -jar my-service "$@" &
在背景中运行该过程,然后使用kill -9 pid
停止。
我想优雅地停止我的网络服务,这意味着它完成了打开连接并拒绝新连接。
github上的Spray-can页面推荐to send it an Akka PoisonPill message
。理想情况下,我想从命令行启动它,尽可能简单。我想可能只附加一个绑定到localhost的HTTP服务器实例,并有一些休息方法停止,并可能诊断web服务。这可行吗?还有什么其他选择?
更新: 我根据答案添加了我能想象的工作,但似乎没有,至少我从未见过我期望在stdout或log中看到的任何消息。实际上,我已经尝试过变体HttpUnbind,PoisonPill,以及一个。愿任何有麻烦的阿卡眼的人看看吗? PS。钩子本身被成功调用,检查它。我发送给jvm的信号是SIGTERM。
/* Simple reaper actor */
class Reaper(refs: ActorRef*) extends Actor {
private val log = Logging(context.system, this)
val watched = ArrayBuffer(refs: _*)
refs foreach context.watch
final def receive = {
case Terminated(ref) =>
watched -= ref
log.info(s"Terminated($ref)")
println(s"Terminated($ref)")
if (watched.isEmpty) {
log.info("Shutting dow the system")
println("Shutting dow the system")
system.shutdown()
}
}
}
// termination hook to gracefully shutdown the service
Runtime.getRuntime.addShutdownHook(new Thread() {
override def run() = {
val reaper = system.actorOf(Props(new Reaper(IO(Http), service)))
//IO(Http) ? Http.Unbind(5.minutes)
IO(Http) ! PoisonPill
}
})
UPDATE2 :所以,不管怎么说它都有效,即 - 当发送PoisonPill时,所有当前的HTTP连接都被关闭了。但我宁愿停止接收新的连接,等待打开以返回响应并关闭。
VERDICT :似乎akka有自己的钩子,因为尽管我的钩子被执行,但是演员们被杀死了所有连接都被关闭了而没有我的行动。如果有人会提供JVM关闭钩子的解决方案,那将是很棒的。我认为这是一个重要的问题,很遗憾,它没有任何好的在线食谱。与此同时,我将尝试使用tcp / http实现正常关闭。
答案 0 :(得分:6)
当我尝试使用SIGTERM和JVM钩子时,我需要阻止钩子线程退出,直到我的关闭序列完成,我根本不知道该怎么做(我在akka中有点缺乏经验,也许我错过了一些明显的解决方案)。
我最终做的是将另一个HTTP侦听器仅附加到localhost,它具有启动关闭的方法(也恰好可以方便其他任务,例如获取服务器状态,触发应用程序中的事件等)。
这可能看起来像这样(我怀疑这可能包含不必要的行为,因此欢迎改进):
在bootstrap中:
implicit val system = ActorSystem(...)
// create and start external service actor
val service = system.actorOf(Props[MyWebServiceActor], "my-web-service")
// create internal service to manage application
val controlService = system.actorOf(Props[ControlServiceActor], "control-service")
implicit val timeout = Timeout(10.seconds)
// start a new HTTP server for external service (notifying control of HTTP listener)
IO(Http).tell(Http.Bind(service, interface = config.interface, port = config.port), controlService)
// start internal server looking at localhost
IO(Http) ? Http.Bind(controlService, interface = "127.0.0.1", port = config.controlPort)
控制服务本身:
class ControlServiceActor extends Actor with HttpService with ActorLogging {
def actorRefFactory = context
implicit val system = context.system
/* Listener of main service */
var listener: ActorRef = _
def receive = {
// this is reply from IO.Http when HTTP listener is bound
case Http.Bound(_) =>
listener = sender()
context.become(mainContext)
}
// http api for graceful stop
val mainContext = runRoute {
path("stop") {
get {
parameter('timeout.as[Int] ? 60) { timeout =>
complete {
// unbind makes listener to reject new connections
context.become(shuttingDownContext)
log.warning(s"Stopping application within $timeout seconds...")
context.watch(listener)
listener ! Http.Unbind(timeout.seconds)
"Stopping..."
}
}
}
}
}
// Shutdown sequence
val shuttingDownContext = ({
// when unbound HTTP listener not accepting connections
case Http.Unbound =>
log.info("Webservice unbound, waiting for active connections to complete")
// when HTTP listener terminated after unbound it has been processed all requests
case Terminated(ref) if ref == listener =>
log.info("Webservice finished, exiting")
system.shutdown()
}: Actor.Receive) orElse runRoute(complete("Shutdown in progress"))
}
答案 1 :(得分:1)
kill -9
会立即销毁进程。你可以使用SIGTERM(kill -15)来触发jvm中的关闭挂钩。
Runtime.getRuntime.addShutdownHook(new Thread() {
def run() = {
//here you can send PoisonPill
}
})