boost-asiohttp2nghttp2

How to gracefully stop a HTTP2 server built with nghttp2 asio


I am aware of how to use nghttp2 asio library to build HTTP2 server and client applications.

The documentation says that there are stop and join APIs for gracefully stopping an HTTP2 server.

Is there any working example of using stop and join? In particular, as soon as listen_and_serve is called, the thread goes to a busy loop. Is it recommended to call stop from a different thread? Unfortunately no clue or example code is given in the documentation.

EDIT:

Here is a working program where I am trying to stop the server on SIGINT.

#include <iostream>
#include <thread>
#include <nghttp2/asio_http2_server.h>

using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;

nghttp2::asio_http2::server::http2 myserver;
void signalHandler( int signum ) {
  std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
  myserver.stop();
  myserver.join();
  exit(0);
}

int main(int argc, char *argv[]) {
  signal(SIGINT, signalHandler);
  std::thread::id this_id = std::this_thread::get_id();
  std::cout << "Main thread running at " << this_id << std::endl;
  boost::system::error_code ec;

  myserver.handle("/api/ping", [](const request &req, const response &res) {
    std::thread::id this_id = std::this_thread::get_id();
    std::cout << "Ping Request received at " << this_id << std::endl;
    req.on_data([](const uint8_t *data, std::size_t len){
      std::cerr.write(reinterpret_cast<const char *>(data), len);
      std::cerr << std::endl;
    });
    res.write_head(200);
    res.end("hello, ping\n");
  });

  if (myserver.listen_and_serve(ec, "0.0.0.0", "8080")) {
    std::cerr << "error: " << ec.message() << std::endl;
  }
}

The execution hangs at myserver.stop() after pressing Control+C. I tried using only myserver.stop() or myserver.join() but without any improvement. If I directly call exit(0) like below, the server stops with a segmentation fault.

void signalHandler( int signum ) {
  std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
  myserver.stop();
  myserver.join();
  exit(0);
}

Any help is appreciated.


Solution

  • The asynchronous parameter in listen_and_serve should be set to true, default is asynchronous = false.

    Note that the server will not exit and wait on the myserver.join() until the last client connection is closed. When you call myserver.close(), the server stops accepting new connections.

    A working solution below:

    #include <iostream>
    #include <thread>
    #include <nghttp2/asio_http2_server.h>
    
    using namespace nghttp2::asio_http2;
    using namespace nghttp2::asio_http2::server;
    
    nghttp2::asio_http2::server::http2 myserver;
    void signalHandler( int signum ) {
      std::cout << "Interrupt signal (" << signum << ") received." << std::endl;
      myserver.stop();
    }
    
    int main(int argc, char *argv[]) {
      signal(SIGINT, signalHandler);
      std::thread::id this_id = std::this_thread::get_id();
      boost::system::error_code ec;
    
      myserver.handle("/api/ping", [](const request &req, const response &res) {
        std::thread::id this_id = std::this_thread::get_id();
        std::cout << "Ping Request received at " << this_id << std::endl;
        req.on_data([](const uint8_t *data, std::size_t len){
          std::cerr.write(reinterpret_cast<const char *>(data), len);
          std::cerr << std::endl;
        });
        res.write_head(200);
        res.end("hello, ping\n");
      });
    
      if (myserver.listen_and_serve(ec, "0.0.0.0", "8080", true)) {
        std::cerr << "error: " << ec.message() << std::endl;
      }
      myserver.join();
    }