Причал: программная остановка вызывает «1 поток не может быть остановлен» - PullRequest
6 голосов
/ 10 января 2011

У меня есть встроенный экземпляр Jetty 6.1.26. Я хочу выключить его с помощью HTTP GET, отправленного на /shutdown. Итак, я создал JettyShutdownServlet:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

 resp.setStatus(202, "Shutting down.");
 resp.setContentType("text/plain");
 ServletOutputStream os = resp.getOutputStream();
 os.println("Shutting down.");
 os.close();
 resp.flushBuffer();

 // Stop the server.
 try {
    log.info("Shutting down the server...");
    server.stop();
 } catch (Exception ex) {
    log.error("Error when stopping Jetty server: "+ex.getMessage(), ex);
 }

Однако, когда я отправляю запрос, Jetty не останавливается - поток продолжает висеть в org.mortbay.thread.QueuedThreadPool на линии с this.wait():

   // We are idle
   // wait for a dispatched job
   synchronized (this)
   {
       if (_job==null)
          this.wait(getMaxIdleTimeMs());
       job=_job;
       _job=null;
   }

...

2011-01-10 20:14:20,375 INFO  org.mortbay.log jetty-6.1.26
2011-01-10 20:14:34,756 INFO  org.mortbay.log Started SocketConnector@0.0.0.0:17283
2011-01-10 20:25:40,006 INFO  org.jboss.qa.mavenhoe.MavenHoeApp Shutting down the server...
2011-01-10 20:25:40,006 INFO  org.mortbay.log Graceful shutdown SocketConnector@0.0.0.0:17283
2011-01-10 20:25:40,006 INFO  org.mortbay.log Graceful shutdown org.mortbay.jetty.servlet.Context@1672bbb{/,null}
2011-01-10 20:25:40,006 INFO  org.mortbay.log Graceful shutdown org.mortbay.jetty.webapp.WebAppContext@18d30fb{/jsp,file:/home/ondra/work/Mavenhoe/trunk/target/classes/org/jboss/qa/mavenhoe/web/jsp}
2011-01-10 20:25:43,007 INFO  org.mortbay.log Stopped SocketConnector@0.0.0.0:17283
2011-01-10 20:25:43,009 WARN  org.mortbay.log 1 threads could not be stopped
2011-01-10 20:26:43,010 INFO  org.mortbay.log Shutdown hook executing
2011-01-10 20:26:43,011 INFO  org.mortbay.log Shutdown hook complete

Он блокируется ровно на одну минуту, затем выключается. Я добавил Graceful shutdown, который должен позволить мне отключить сервер от сервлета; Однако, это не работает, как вы можете видеть из журнала.

Я решил это так:

Server server = new Server( PORT );
server.setGracefulShutdown( 3000 );
server.setStopAtShutdown(true);
...
server.start();

if( server.getThreadPool() instanceof QueuedThreadPool ){
   ((QueuedThreadPool) server.getThreadPool()).setMaxIdleTimeMs( 2000 );
}

setMaxIdleTimeMs() необходимо вызывать после start(), так как threadPool создается в start(). Однако потоки уже созданы и ожидают, поэтому он применяется только после того, как все потоки используются хотя бы один раз.

Я не знаю, что еще делать, кроме некоторого ужаса, такого как прерывание всех потоков или System.exit().

Есть идеи? Есть хороший способ?

1 Ответ

11 голосов
/ 11 января 2011

Изящный не делает то, что вы думаете, он делает это - он позволяет корректно завершить работу сервера, но он не не позволяет вам отключиться изнутри сервлета.как описано в сообщении списка рассылки, на которое вы ссылались - вы пытаетесь остановить сервер, пока вы все еще обрабатываете соединение внутри сервера.*

// Stop the server.
new Thread()
{
   public void run() {
     try {
        log.info("Shutting down the server...");
        server.stop();
        log.info("Server has stopped.");
     } catch (Exception ex) {
        log.error("Error when stopping Jetty server: "+ex.getMessage(), ex);
     }
   }
}.start();

Таким образом сервлет может завершить обработку во время выключения сервера и не будет задерживать процесс выключения.

...