nghttpx: Add HTTP/3 graceful shutdown

This commit is contained in:
Tatsuhiro Tsujikawa 2021-08-31 14:06:59 +09:00
parent e998d125ab
commit 17012654e1
2 changed files with 87 additions and 0 deletions

View File

@ -76,6 +76,28 @@ fail:
}
} // namespace
namespace {
void shutdown_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
auto upstream = static_cast<Http3Upstream *>(w->data);
auto handler = upstream->get_client_handler();
if (upstream->submit_goaway() != 0) {
delete handler;
}
}
} // namespace
namespace {
void prepare_cb(struct ev_loop *loop, ev_prepare *w, int revent) {
auto upstream = static_cast<Http3Upstream *>(w->data);
auto handler = upstream->get_client_handler();
if (upstream->check_shutdown() != 0) {
delete handler;
}
}
} // namespace
namespace {
size_t downstream_queue_size(Worker *worker) {
auto &downstreamconf = *worker->get_downstream_config();
@ -104,11 +126,20 @@ Http3Upstream::Http3Upstream(ClientHandler *handler)
ev_timer_init(&idle_timer_, idle_timeoutcb, 0.,
quicconf.upstream.timeout.idle);
idle_timer_.data = this;
ev_timer_init(&shutdown_timer_, shutdown_timeout_cb, 0., 0.);
shutdown_timer_.data = this;
ev_prepare_init(&prep_, prepare_cb);
prep_.data = this;
ev_prepare_start(handler_->get_loop(), &prep_);
}
Http3Upstream::~Http3Upstream() {
auto loop = handler_->get_loop();
ev_prepare_stop(loop, &prep_);
ev_timer_stop(loop, &shutdown_timer_);
ev_timer_stop(loop, &idle_timer_);
ev_timer_stop(loop, &timer_);
@ -2400,4 +2431,55 @@ void Http3Upstream::log_response_headers(
<< ss.str();
}
int Http3Upstream::check_shutdown() {
auto worker = handler_->get_worker();
if (!worker->get_graceful_shutdown()) {
return 0;
}
ev_prepare_stop(handler_->get_loop(), &prep_);
return start_graceful_shutdown();
}
int Http3Upstream::start_graceful_shutdown() {
int rv;
if (ev_is_active(&shutdown_timer_)) {
return 0;
}
rv = nghttp3_conn_submit_shutdown_notice(httpconn_);
if (rv != 0) {
ULOG(FATAL, this) << "nghttp3_conn_submit_shutdown_notice: "
<< nghttp3_strerror(rv);
return -1;
}
handler_->signal_write();
auto t = ngtcp2_conn_get_pto(conn_);
ev_timer_set(&shutdown_timer_, static_cast<ev_tstamp>(t) * 3 / NGTCP2_SECONDS,
0.);
ev_timer_start(handler_->get_loop(), &shutdown_timer_);
return 0;
}
int Http3Upstream::submit_goaway() {
int rv;
rv = nghttp3_conn_shutdown(httpconn_);
if (rv != 0) {
ULOG(FATAL, this) << "nghttp3_conn_shutdown: " << nghttp3_strerror(rv);
return -1;
}
handler_->signal_write();
return 0;
}
} // namespace shrpx

View File

@ -144,11 +144,16 @@ public:
int http_recv_data(Downstream *downstream, const uint8_t *data,
size_t datalen);
int handshake_completed();
int check_shutdown();
int start_graceful_shutdown();
int submit_goaway();
private:
ClientHandler *handler_;
ev_timer timer_;
ev_timer idle_timer_;
ev_timer shutdown_timer_;
ev_prepare prep_;
ngtcp2_cid initial_client_dcid_;
ngtcp2_conn *conn_;
quic::Error last_error_;