状況
Spark FrameworkというSinatraっぽい軽量サーバを使ってGroovyでWebAPIのサーバを書いてます。
sparkjava.com
サーバを停止する処理を呼ぶと停止処理中に固まってしまうという現象が起きてました。
実装
サーバを停止する方法は公式ドキュメントにある通り簡単なものです。
Stopping the Server
By calling the stop() method the server is stopped and all routes are cleared.
stop();
以下のようにAPIとして呼べるようにしてあります。
get "/stop", { req, res -> stop() }
が、以下のようなエラーが出てしまいます。
[Thread-1] INFO org.eclipse.jetty.util.log - Logging initialized @975ms
[Thread-1] INFO spark.webserver.JettySparkServer - == Spark has ignited ...
[Thread-1] INFO spark.webserver.JettySparkServer - >> Listening on 0.0.0.0:8010
[Thread-1] INFO org.eclipse.jetty.server.Server - jetty-9.3.2.v20150730
[Thread-1] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@3ab422de{HTTP/1.1,[http/1.1]}{0.0.0.0:8010}
[Thread-1] INFO org.eclipse.jetty.server.Server - Started @1089ms
[qtp1972788076-17] INFO spark.webserver.MatcherFilter - The requested route [/] has not been mapped in Spark
[qtp1972788076-20] INFO spark.webserver.JettySparkServer - >>> Spark shutting down ...
[qtp1972788076-20] INFO org.eclipse.jetty.server.ServerConnector - Stopped ServerConnector@3ab422de{HTTP/1.1,[http/1.1]}{0.0.0.0:8010}
[qtp1972788076-20] ERROR spark.webserver.JettySparkServer - stop failed
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Thread.join(Thread.java:1253)
at org.eclipse.jetty.util.thread.QueuedThreadPool.doStop(QueuedThreadPool.java:161)
at org.eclipse.jetty.util.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:89)
at org.eclipse.jetty.util.component.ContainerLifeCycle.stop(ContainerLifeCycle.java:143)
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStop(ContainerLifeCycle.java:161)
at org.eclipse.jetty.server.handler.AbstractHandler.doStop(AbstractHandler.java:73)
at org.eclipse.jetty.server.Server.doStop(Server.java:476)
at org.eclipse.jetty.util.component.AbstractLifeCycle.stop(AbstractLifeCycle.java:89)
at spark.webserver.JettySparkServer.stop(JettySparkServer.java:148)
at spark.SparkInstance.stop(SparkInstance.java:317)
at spark.Spark.stop(Spark.java:987)
at spark.Spark$stop$0.callStatic(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:198)
at FooWebapiService$_main_closure5.doCall(fooWebapi.groovy:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1019)
at groovy.lang.Closure.call(Closure.java:426)
at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:53)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:105)
at com.sun.proxy.$Proxy5.handle(Unknown Source)
at spark.RouteImpl$1.handle(RouteImpl.java:58)
at spark.webserver.MatcherFilter.doFilter(MatcherFilter.java:162)
at spark.webserver.JettyHandler.doHandle(JettyHandler.java:61)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:189)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:119)
at org.eclipse.jetty.server.Server.handle(Server.java:517)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:302)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:242)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:245)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:75)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceAndRun(ExecuteProduceConsume.java:213)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:147)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:654)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:572)
at java.lang.Thread.run(Thread.java:745)
修正
調べるとGitHubにIssueがありました
github.com
どうやら停止するときは別スレッドにしておくと良いらしい。なるほどー。
さっそく修正してみる。
get "/stop", { req, res -> Thread.start {stop()} }
直ったー。(^_^)v
[Thread-1] INFO org.eclipse.jetty.util.log - Logging initialized @899ms
[Thread-1] INFO spark.webserver.JettySparkServer - == Spark has ignited ...
[Thread-1] INFO spark.webserver.JettySparkServer - >> Listening on 0.0.0.0:8010
[Thread-1] INFO org.eclipse.jetty.server.Server - jetty-9.3.2.v20150730
[Thread-1] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@6591cb3b{HTTP/1.1,[http/1.1]}{0.0.0.0:8010}
[Thread-1] INFO org.eclipse.jetty.server.Server - Started @1015ms
[Thread-11] INFO spark.webserver.JettySparkServer - >>> Spark shutting down ...
[Thread-11] INFO org.eclipse.jetty.server.ServerConnector - Stopped ServerConnector@6591cb3b{HTTP/1.1,[http/1.1]}{0.0.0.0:8010}
[Thread-11] INFO spark.webserver.JettySparkServer - done