Встроенная пристань, закрытие открытых соединений во время изящного завершения - PullRequest
1 голос
/ 25 мая 2019

Я написал базовый встроенный джет-сервер (с джерси для определения конечных точек), и мне нужно, чтобы он завершился изящно (в ответ на SIGINT). Я хотел бы, чтобы все запросы в полете завершили обработку и возвращали результаты запрашивающей стороне (вплоть до некоторого времени ожидания), не принимая новых подключений / запросов.

Текущее поведение, которое я наблюдаю, заключается в том, что запросы в полете выполняются правильно, но соединения с клиентами прерываются (поэтому они не получают ответы на свои запросы).

При создании экземпляра Server я устанавливаю setStopAtShutdown на true и устанавливаю значение для setStopTimeout. Я также настраиваю StatisticsHandler. Из того, что я могу сказать из документов, это то, что требуется для включения изящного завершения.

Вот мой настроенный сервер:

// For additional Jetty configuration options see:
// https://www.eclipse.org/jetty/documentation/current/embedding-jetty.html#_like_jetty_xml
public static Server createServer(
    int port, int shutdownGracePeriodMillis, int httpServerThreads, int httpIdleTimeoutMillis) {
    // Create server
    QueuedThreadPool threadPool = new QueuedThreadPool();
    threadPool.setMaxThreads(httpServerThreads);
    Server server = new Server(threadPool);
    HttpConfiguration config = new HttpConfiguration();
    ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(config));
    http.setPort(port);
    http.setIdleTimeout(httpIdleTimeoutMillis);
    server.addConnector(http);

    // Enable StatisticsHandler (required for graceful termination)
    StatisticsHandler stats = new StatisticsHandler();
    stats.setHandler(server.getHandler());
    server.setHandler(stats);
    ServerConnectionStatistics.addToAllConnectors(server);

    // Configure graceful termination
    server.setStopAtShutdown(true);
    server.setStopTimeout(shutdownGracePeriodMillis);

    // Associate Jersey with Jetty
    JettyHttpContainer container =
        ContainerFactory.createContainer(JettyHttpContainer.class, new AppResourceConfig());
    server.setHandler(container);

    return server;
}

Вот мой ресурс Джерси. Он использует Thread.sleep для имитации некоторых длительных запросов, которые необходимо выполнить до выключения сервера.

@POST
@Consumes("application/json")
@Produces(MediaType.TEXT_PLAIN)
public String testEndpoint() {
    for(int i = 0; i < 4; i++) {
        try {
            logger.info("Number: " + i);
            Thread.sleep(5000);
        } catch (Exception e) { }
    }

    logger.info("Request completed!");

    return "Hello, world!\n";
}

Я запускаю сервер и запускаю следующую команду curl

curl -v --header "Content-Type: application/json" \
  --request POST \
  --data '' \
  http://localhost:4200/testEndpoint

Когда я отправляю SIGINT процессу сервера, пока этот запрос все еще ожидает ответа, который я вижу на сервере:

INFO  c.a.a.s.resources.Resource - Number: 0
INFO  c.a.a.s.resources.Resource - Number: 1
^C {{NOTE: SIGINT issued here}}
[Thread-1] INFO  o.e.jetty.server.AbstractConnector - Stopped ServerConnector@32c726ee{HTTP/1.1,[http/1.1]}{0.0.0.0:4200}
INFO  c.a.a.s.resources.AuctionResource - Number: 2
INFO  c.a.a.s.resources.AuctionResource - Number: 3
INFO  c.a.a.s.resources.AuctionResource - Request completed!

Из журналов сервера видно, что запрос выполнен правильно. Команда curl никогда не получает ответ "Hello, world!" хотя (что он делает в обычном непрерывном запросе).

Вывод curl выглядит следующим образом:

*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 4200 (#0)
> POST /testEndpoint HTTP/1.1
> Host: localhost:4200
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 0
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server

Я ожидал, что получу правильный ответ от службы, но вместо этого получу пустой ответ от сервера. Какая дополнительная конфигурация требуется, чтобы не закрывать соединения запросов в полете во время корректного завершения для встроенного сервера Jetty?

...