http: properly respond to HTTP request during shutdown

Makes sure we respond to the client as the HTTP request attempts to submit a task to
the thread pool during server shutdown.

Roughly what happens:

1) The server receives an HTTP request and starts calling http_request_cb().
2) Meanwhile on another thread, shutdown is triggered which calls InterruptHTTPServer()
   and unregisters libevent http_request_cb() callback and interrupts the thread pool.
3) The request (step 1) resumes and tries to submit a task to the now-interrupted server.

This fix detects failed submissions immediately, and the server responds with
HTTP_SERVICE_UNAVAILABLE.
This commit is contained in:
furszy 2026-02-12 14:08:22 -05:00
parent 59d24bd5dd
commit 726b3663cc
No known key found for this signature in database
GPG Key ID: 5DD23CCC686AA623

View File

@ -211,7 +211,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
}
}
}
auto hreq{std::make_unique<HTTPRequest>(req, *static_cast<const util::SignalInterrupt*>(arg))};
auto hreq{std::make_shared<HTTPRequest>(req, *static_cast<const util::SignalInterrupt*>(arg))};
// Early address-based allow check
if (!ClientAllowed(hreq->GetPeer())) {
@ -258,7 +258,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
return;
}
auto item = [req = std::move(hreq), in_path = std::move(path), fn = i->handler]() {
auto item = [req = hreq, in_path = std::move(path), fn = i->handler]() {
std::string err_msg;
try {
fn(req.get(), in_path);
@ -276,7 +276,13 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
req->WriteReply(HTTP_INTERNAL_SERVER_ERROR, err_msg);
};
[[maybe_unused]] auto _{g_threadpool_http.Submit(std::move(item))};
if (auto res = g_threadpool_http.Submit(std::move(item)); !res.has_value()) {
Assume(hreq.use_count() == 1); // ensure request will be deleted
// Both SubmitError::Inactive and SubmitError::Interrupted mean shutdown
LogWarning("HTTP request rejected during server shutdown: '%s'", SubmitErrorString(res.error()));
hreq->WriteReply(HTTP_SERVICE_UNAVAILABLE, "Request rejected during server shutdown");
return;
}
} else {
hreq->WriteReply(HTTP_NOT_FOUND);
}