Web services 喷雾罐Web服务正常关闭
我有基于spray.io的Web服务,它作为独立的jar运行(我使用Web services 喷雾罐Web服务正常关闭,web-services,scala,akka,spray,Web Services,Scala,Akka,Spray,我有基于spray.io的Web服务,它作为独立的jar运行(我使用sbt汇编,然后使用java-jar myws.jar)。它的bootsrap与spray示例中的bootsrap非常相似,如下所示: /** Bootstrap */ object Boot extends App { // we need an ActorSystem to host our application in implicit val system = ActorSystem("my-system")
sbt汇编
,然后使用java-jar myws.jar
)。它的bootsrap与spray示例中的bootsrap非常相似,如下所示:
/** 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我的服务“$@”和运行该过程,然后使用kill-9pid
停止
我想优雅地停止我的Web服务,这意味着它完成打开的连接并拒绝新的连接
喷雾罐页面建议向其发送Akka毒药信息
。理想情况下,我希望从命令行启动它,尽可能简单。我想可能需要再附加一个绑定到本地主机的HTTP服务器实例,并停止一些rest方法,还可能需要诊断Web服务。可行吗?其他的选择是什么
更新:
根据答案,我补充了我能想象到的必须要起作用的东西,但似乎没有,至少我从来没有在stdout或log中看到过我期望看到的任何消息。事实上,我试过HttpUnbind和毒药,一起试过,一个一个试过。任何一个目光敏锐的人可以看看这个吗?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:因此,它以某种方式工作,即-当发送毒药时,所有当前HTTP连接都被关闭。但我宁愿停止接收新的连接,等待open返回响应并关闭
判决:阿克卡似乎有自己的钩子,因为尽管我的钩子被执行了,演员们还是被杀了,所有的联系都在我不采取行动的情况下关闭了。如果有人能提供JVM关闭钩子的解决方案,那就太好了。我认为这是一个重要的问题,非常遗憾的是,网上没有任何好的食谱。同时,我将尝试使用tcp/http实现优雅的关闭。kill-9
将立即销毁进程。您可以使用SIGTERM(kill-15)在jvm中触发关闭挂钩
Runtime.getRuntime.addShutdownHook(new Thread() {
def run() = {
//here you can send PoisonPill
}
})
当我尝试使用SIGTERM和JVM钩子时,我需要阻止钩子线程退出,直到我的关闭序列完成,我只是不知道如何做(我在akka方面有点经验不足,所以可能错过了一些明显的解决方案)
我最后做的是只将一个HTTP侦听器附加到localhost,该侦听器具有启动关机的方法(同时,它还方便执行其他任务,如获取服务器状态、触发应用程序中的事件等)
这可能是这样的(我怀疑这可能包含不必要的操作,因此欢迎改进):
在引导中:
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"))
}
您可以使用Http.Unbind
消息通知服务器在超时后停止侦听新连接并关闭打开的连接。看见有一些休息的方法来停止是绝对可能的,看看这个喷雾的例子(虽然它没有优雅地停止)为例:我尝试了这里和那里,但它似乎不起作用。请看一下更新。@jrudolph我在问题中更新了:钩子被激活,但akka系统被其他东西关闭(可能是它自己的钩子),因此进程中的连接被关闭(客户端收到错误消息,连接被remore关闭)。我希望打开的连接完成,并仅在此之后关闭。似乎这与解除绑定无关。最终我明白了我的错误所在,没有人指出将解除绑定的发送到IO(Http)
本身是无用的,应该发送给侦听器。是的,您需要向所有侦听器发送Http.Unbind
,然后等待所有侦听器以阻塞方式发出Unbind
响应,而不必从关闭钩子返回,否则进程将在清理之前关闭。请,您能否详细说明在SIGTERM的情况下,关闭顺序如何?比如说,JVM将运行钩子,它如何知道所需的进程已经完成?类似于所描述的(因为spray基于akka)您可以向spray参与者发送一些消息,并使用been
来更改行为(停止接收连接)。这一切似乎都没有用,因为在SIGTERM上,所有人都被其他东西杀死了,钩子也没用。或者我做错了什么。这是可行的,但hook必须以某种方式阻止执行,并等待所有必要的步骤完成-例如,一些演员关闭,或者某些序列结束。这件事变得非同小可,我在网上找不到任何有用的东西。我放弃了尝试,继续以公认的答案解决问题。就我个人而言,我希望用SIGTERM实现variant,但是……对于开发环境来说,这是一个不错的解决方案!但对于生产环境,您通常希望在服务器重新启动时(尤其是在需要关闭操作以保持环境的其余部分正常运行的情况下),关闭代码也能正常运行,这是事实,但是我还没有找到更好的解决方案。小的输入错误-这不应该是//关闭序列
?@dmitry除了Http之外还会发送一个毒药丸
。考虑到spray的自述页面上说用毒药丸关闭它,解除绑定是个好主意@我记得我试过毒丸,它以某种直截了当的方式杀死了演员,关闭了连接,但没有等待完成。