Loading src/httpd.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -713,6 +713,39 @@ void libhttppp::HttpEvent::_dispatchH1Request(HttpRequest &cureq, size_t consume cureq2.slots[0].csock->setNonBlock(); netplus::reattachConnection(connOwner); }); if (accepted) return; // Pool is already at h1DispatchQueueMax pending tasks -- every worker is presumably // busy with something slow (or stuck), and every one of those already-queued // requests' sockets is detached (invisible to the idle reaper, un-timed until a // worker picks them up). Piling this one up behind them too is exactly the same // production incident h2DispatchQueueMax exists to prevent for H2, just relocated // to H1: eventually a worker frees up and discovers the peer gave up long ago, // starting the local close far too late (LAST_ACK never gets ACKed). Answer 503 // right here instead, synchronously, without ever calling the possibly-slow // RequestEvent -- reclaim the socket from sockBox (submit() never queued the // lambda that captured it, so sockBox's refcount dropped back to this scope's own // copy, same as _dispatchH2Stream's trBox) and write the response directly. cureq.slots[0].csock = std::move(*sockBox); cureq.slots[0].csock->setBlock(); cureq.slots[0].csock->setTimeout(kH1OffloadSocketTimeoutMs); try { HttpResponse busy; busy.setState(HTTP503); busy.setContentType("text/plain"); static const std::string kBusyMsg = "server overloaded, try again shortly"; busy.send(cureq, kBusyMsg, static_cast<int>(kBusyMsg.size())); cureq.flushSendData(); } catch (...) { // Best-effort -- the connection is being closed either way below. } cureq.slots[0].csock->close(); // Leave csock null afterward, exactly like detachConnection()'s own post-condition // above and the accepted-offload path's WebSocket-handoff case -- IoEventHandler's // existing null-csock check right after its RequestEvent(con&,...) call site then // safely stops touching this connection instead of trying to flush/re-arm an fd // that's already closed. cureq.slots[0].csock.reset(); return; } // Connection lookup/detach failed (shouldn't happen while we're still holding Loading Loading
src/httpd.cpp +33 −0 Original line number Diff line number Diff line Loading @@ -713,6 +713,39 @@ void libhttppp::HttpEvent::_dispatchH1Request(HttpRequest &cureq, size_t consume cureq2.slots[0].csock->setNonBlock(); netplus::reattachConnection(connOwner); }); if (accepted) return; // Pool is already at h1DispatchQueueMax pending tasks -- every worker is presumably // busy with something slow (or stuck), and every one of those already-queued // requests' sockets is detached (invisible to the idle reaper, un-timed until a // worker picks them up). Piling this one up behind them too is exactly the same // production incident h2DispatchQueueMax exists to prevent for H2, just relocated // to H1: eventually a worker frees up and discovers the peer gave up long ago, // starting the local close far too late (LAST_ACK never gets ACKed). Answer 503 // right here instead, synchronously, without ever calling the possibly-slow // RequestEvent -- reclaim the socket from sockBox (submit() never queued the // lambda that captured it, so sockBox's refcount dropped back to this scope's own // copy, same as _dispatchH2Stream's trBox) and write the response directly. cureq.slots[0].csock = std::move(*sockBox); cureq.slots[0].csock->setBlock(); cureq.slots[0].csock->setTimeout(kH1OffloadSocketTimeoutMs); try { HttpResponse busy; busy.setState(HTTP503); busy.setContentType("text/plain"); static const std::string kBusyMsg = "server overloaded, try again shortly"; busy.send(cureq, kBusyMsg, static_cast<int>(kBusyMsg.size())); cureq.flushSendData(); } catch (...) { // Best-effort -- the connection is being closed either way below. } cureq.slots[0].csock->close(); // Leave csock null afterward, exactly like detachConnection()'s own post-condition // above and the accepted-offload path's WebSocket-handoff case -- IoEventHandler's // existing null-csock check right after its RequestEvent(con&,...) call site then // safely stops touching this connection instead of trying to flush/re-arm an fd // that's already closed. cureq.slots[0].csock.reset(); return; } // Connection lookup/detach failed (shouldn't happen while we're still holding Loading