Commit 2290ebaa authored by jan.koester's avatar jan.koester
Browse files

test

parent 6fda2e22
Loading
Loading
Loading
Loading
+28 −4
Original line number Diff line number Diff line
@@ -375,10 +375,10 @@ static std::vector<uint8_t> h3BuildResponse(uint16_t status_code,

libhttppp::HttpEvent::HttpEvent(std::vector<netplus::socket*> serversocket, int timeout,
                                 size_t h2OffloadThreads, int idleTimeoutSeconds,
                                 size_t h1OffloadThreads)
                                 size_t h1OffloadThreads, size_t h2DispatchQueueMax)
    : netplus::event(serversocket, timeout, idleTimeoutSeconds) {
    if (h2OffloadThreads > 0)
        _h2DispatchPool = std::make_unique<netplus::ThreadPool>(h2OffloadThreads);
        _h2DispatchPool = std::make_unique<netplus::ThreadPool>(h2OffloadThreads, h2DispatchQueueMax);
    if (h1OffloadThreads > 0)
        _h1DispatchPool = std::make_unique<netplus::ThreadPool>(h1OffloadThreads);
    // Bounded like quicDispatchPool() in libnetplus (same rationale: this
@@ -542,7 +542,7 @@ bool libhttppp::HttpEvent::_dispatchH2Stream(HttpRequest &cureq,
            // stays effectively unique since nothing else ever sees this
            // particular shared_ptr.
            auto trBox = std::make_shared<std::unique_ptr<HttpRequest>>(std::move(tempreq_ptr));
            _h2DispatchPool->submit(
            bool accepted = _h2DispatchPool->submit(
                [this, connOwner, trBox, sid, tid, args]() mutable {
                    // The ONLY blocking call in this task — touches
                    // *trBox (private to this task) only, never
@@ -575,7 +575,31 @@ bool libhttppp::HttpEvent::_dispatchH2Stream(HttpRequest &cureq,
                    if (cureq2.SendData.pos < cureq2.SendData.size())
                        netplus::requestWritablePoll(cureq2);
                });
            return true;
            if (accepted) return true;

            // Pool is already at h2DispatchQueueMax pending tasks -- every worker is presumably
            // busy with something slow (or stuck) and piling this stream up behind them too
            // would just be another request nobody notices is waiting forever (the exact
            // production incident this bound exists to prevent). Answer 503 right here instead,
            // synchronously, without ever calling RequestEvent -- reclaim tempreq_ptr from
            // trBox (submit() never queued the lambda that captured it, so trBox's refcount
            // dropped back to this scope's own copy) and reuse the same
            // HttpResponse::send()-sets-:res-*-pseudo-headers mechanism sendError() callers rely
            // on, then finish exactly like the normal synchronous path below.
            tempreq_ptr = std::move(*trBox);
            try {
                HttpResponse busy;
                busy.setState(HTTP503);
                busy.setContentType("text/plain");
                static const std::string kBusyMsg = "server overloaded, try again shortly";
                busy.send(*tempreq_ptr, kBusyMsg, static_cast<int>(kBusyMsg.size()));
            } catch (const HTTPException &) {
                // Same "no response produced" fallback _finishH2Dispatch already has for a
                // RequestEvent that threw above -- sends RST_STREAM(INTERNAL_ERROR) instead of
                // hanging the stream.
            }
            _finishH2Dispatch(cureq, out, sid, std::move(tempreq_ptr), tid, args);
            return false;
        }
        // Connection lookup failed (shouldn't happen while we're still
        // holding event_mutex for this call) — fall through to the
+8 −1
Original line number Diff line number Diff line
@@ -68,9 +68,16 @@ namespace libhttppp {
        // safely needs a detach/reattach round trip through netplus::detachConnection()/
        // reattachConnection() rather than H2's "hand off a throwaway tempreq" trick -- see
        // _dispatchH1Request's doc comment for the full mechanics.
        // h2DispatchQueueMax: caps how many H2 streams may be queued in _h2DispatchPool waiting
        // for a worker (see netplus::ThreadPool's own max_queue_size). 0 (the default) keeps the
        // pool unbounded for every existing caller -- exactly today's behavior, where a stuck or
        // saturated pool means every subsequent stream on every connection waits forever with no
        // way to notice. A positive value makes _dispatchH2Stream respond 503 immediately once
        // the pool is this full instead of queuing behind it. Has no effect if h2OffloadThreads
        // is 0 (nothing to bound).
        HttpEvent(std::vector<netplus::socket*> serversocket,int timeout = 1000,
                  size_t h2OffloadThreads = 0, int idleTimeoutSeconds = 0,
                  size_t h1OffloadThreads = 0);
                  size_t h1OffloadThreads = 0, size_t h2DispatchQueueMax = 0);

        // Return true to have this stream's RequestEvent run on the H2
        // offload thread pool instead of inline in the frame-processing