Commit 735b2e91 authored by jan.koester's avatar jan.koester
Browse files

timeout added upstream

parent 0fd376c4
Loading
Loading
Loading
Loading
+4 −0
Changes for config/proxyplus.yaml: 4 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -77,6 +77,10 @@ proxyplus:
    # once; idle_timeout_seconds discards (rather than reuses) one that's sat idle longer.
    upstream_pool_max_idle_per_origin: 8
    upstream_pool_idle_timeout_seconds: 60
    # Bounds both the TCP/TLS connect attempt and the wait for the upstream's response for
    # every proxied request. Raise this for a legitimately slow-but-alive upstream (a
    # cold-starting backend, a long-running API call, ...) that needs more than 60s.
    upstream_request_timeout_seconds: 60

  pid_file: "/run/proxyplus.pid"
  recovery_mode: false
+3 −0
Changes for src/config/BootstrapConfig.cpp: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ const std::set<std::string> &knownLeafPatterns() {
        "/proxyplus/process/idle_connection_timeout_seconds",
        "/proxyplus/process/upstream_pool_max_idle_per_origin",
        "/proxyplus/process/upstream_pool_idle_timeout_seconds",
        "/proxyplus/process/upstream_request_timeout_seconds",
        "/proxyplus/pid_file",
        "/proxyplus/recovery_mode",
        "/proxyplus/maintenance_mode",
@@ -232,6 +233,8 @@ void BootstrapConfig::loadAndValidate() {
        readInt(conf, "/proxyplus/process/upstream_pool_max_idle_per_origin", 8);
    cfg.upstreamPoolIdleTimeoutSeconds =
        readInt(conf, "/proxyplus/process/upstream_pool_idle_timeout_seconds", 60);
    cfg.upstreamRequestTimeoutSeconds =
        readInt(conf, "/proxyplus/process/upstream_request_timeout_seconds", 60);
    cfg.pidFile = readValue(conf, "/proxyplus/pid_file", "");

    cfg.recoveryMode = readBool(conf, "/proxyplus/recovery_mode", false) ? RecoveryMode::Recover
+9 −0
Changes for src/config/BootstrapConfig.h: 9 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -110,6 +110,15 @@ struct AppConfig {
    int upstreamPoolMaxIdlePerOrigin = 8;
    int upstreamPoolIdleTimeoutSeconds = 60;

    // Bounds HttpClient's connect attempt AND its wait for the upstream's response (see
    // libhttppp::HttpClient's timeoutSec ctor param / setTimeout()) for every proxied
    // request -- previously a literal 60 hardcoded at the one call site
    // (HttpProxyController::RequestEvent), which meant a legitimately slow-but-alive
    // upstream (a cold-starting backend, a long-running API call, ...) had no way to get
    // more headroom without a code change. 60s default matches that prior hardcoded value,
    // so an unset config keeps today's behavior.
    int upstreamRequestTimeoutSeconds = 60;

    RecoveryMode recoveryMode = RecoveryMode::Normal;
    MaintenanceMode maintenanceMode = MaintenanceMode::Off;
};
+14 −8
Changes for src/http/HttpProxyServer.cpp: 14 added lines, 8 removed lines.
Original line number Diff line number Diff line
@@ -116,7 +116,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo
                                          lb::LoadBalancer &loadBalancer,
                                          http::UpstreamConnectionPool &connectionPool,
                                          tls::AcmeChallengeStore *acmeChallenges,
                                          int idleTimeoutSeconds)
                                          int idleTimeoutSeconds,
                                          int upstreamTimeoutSeconds)
    // H2 dispatch now runs through the same offload pool as H1 (see shouldOffloadH2Dispatch
    // below): both RequestEvent calls do real backend I/O, so both need off the shared
    // epoll/kqueue listener workers to avoid one bursty connection starving new TLS
@@ -136,7 +137,8 @@ HttpProxyController::HttpProxyController(std::vector<netplus::socket *> serverSo
    , _pluginManager(pluginManager)
    , _loadBalancer(loadBalancer)
    , _connectionPool(connectionPool)
    , _acmeChallenges(acmeChallenges) {
    , _acmeChallenges(acmeChallenges)
    , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) {
}

bool HttpProxyController::shouldOffloadH2Dispatch(libhttppp::HttpRequest &, uint32_t) const {
@@ -505,7 +507,7 @@ void HttpProxyController::RequestEvent(libhttppp::HttpRequest &curreq, const int
            // falling back to HTTP/2 then HTTP/1.1 over TLS (or straight to H1 for a cleartext
            // upstream) when a new connection actually needs constructing -- see HttpClient
            // ctor in libhttppp/src/http.cpp for the fallback ladder.
            auto clientPtr = _connectionPool.acquire(upstream, /*vers=*/3, /*timeoutSec=*/60,
            auto clientPtr = _connectionPool.acquire(upstream, /*vers=*/3, _upstreamTimeoutSeconds,
                                                      trustPolicyFor(matched));
            libhttppp::HttpClient &client = *clientPtr;
            poolGuard.arm(_connectionPool, upstream, std::move(clientPtr));
@@ -660,7 +662,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce
                                  lb::LoadBalancer &loadBalancer,
                                  http::UpstreamConnectionPool &connectionPool,
                                  tls::AcmeChallengeStore *acmeChallenges,
                                  int idleTimeoutSeconds)
                                  int idleTimeoutSeconds,
                                  int upstreamTimeoutSeconds)
    : _listener(listener)
    , _tlsActive(!listener.tlsProfile.empty())
    , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certPath,
@@ -671,7 +674,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener, std::string ce
    , _loadBalancer(loadBalancer)
    , _connectionPool(connectionPool)
    , _acmeChallenges(acmeChallenges)
    , _idleTimeoutSeconds(idleTimeoutSeconds) {
    , _idleTimeoutSeconds(idleTimeoutSeconds)
    , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) {
    bindAndListen();
}

@@ -681,7 +685,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener,
                                  plugin::PluginManager &pluginManager, lb::LoadBalancer &loadBalancer,
                                  http::UpstreamConnectionPool &connectionPool,
                                  tls::AcmeChallengeStore *acmeChallenges,
                                  int idleTimeoutSeconds)
                                  int idleTimeoutSeconds,
                                  int upstreamTimeoutSeconds)
    : _listener(listener)
    , _tlsActive(true)
    , _httpd(std::make_unique<libhttppp::HttpD>(listener.address, listener.port, 512, certsByHostname))
@@ -691,7 +696,8 @@ HttpProxyServer::HttpProxyServer(config::ListenerConfig listener,
    , _loadBalancer(loadBalancer)
    , _connectionPool(connectionPool)
    , _acmeChallenges(acmeChallenges)
    , _idleTimeoutSeconds(idleTimeoutSeconds) {
    , _idleTimeoutSeconds(idleTimeoutSeconds)
    , _upstreamTimeoutSeconds(upstreamTimeoutSeconds) {
    bindAndListen();
}

@@ -711,7 +717,7 @@ void HttpProxyServer::run() {
                                    _listener.address + ":" + std::to_string(_listener.port),
                                    _tlsActive, _configStore, _authService, _pluginManager,
                                    _loadBalancer, _connectionPool, _acmeChallenges,
                                    _idleTimeoutSeconds);
                                    _idleTimeoutSeconds, _upstreamTimeoutSeconds);
    controller.runEventloop();
}

+14 −5
Changes for src/http/HttpProxyServer.h: 14 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ public:
    // idleTimeoutSeconds is forwarded straight to the libhttppp::HttpEvent base (see its own
    // doc comment in httpd.h) -- default 0 keeps today's behavior for any caller that doesn't
    // pass it explicitly; main.cpp's real call sites pass AppConfig::idleConnectionTimeoutSeconds.
    // upstreamTimeoutSeconds bounds each proxied request's own connect+response wait (see
    // UpstreamConnectionPool::acquire()'s timeoutSec) -- default 60 matches the value that used
    // to be hardcoded at the RequestEvent call site; main.cpp's real call sites pass
    // AppConfig::upstreamRequestTimeoutSeconds.
    HttpProxyController(std::vector<netplus::socket *> serverSockets,
                         std::string listenerLabel,
                         bool tlsActive,
@@ -38,7 +42,8 @@ public:
                         lb::LoadBalancer &loadBalancer,
                         http::UpstreamConnectionPool &connectionPool,
                         tls::AcmeChallengeStore *acmeChallenges = nullptr,
                         int idleTimeoutSeconds = 0);
                         int idleTimeoutSeconds = 0,
                         int upstreamTimeoutSeconds = 60);

    void RequestEvent(libhttppp::HttpRequest &curreq, const int tid, ULONG_PTR args) override;

@@ -99,6 +104,7 @@ private:
    lb::LoadBalancer &_loadBalancer;
    http::UpstreamConnectionPool &_connectionPool;
    tls::AcmeChallengeStore *_acmeChallenges;
    int _upstreamTimeoutSeconds;
};

// Binds the listener socket(s) *at construction time* (see main.cpp / spec "Privilege
@@ -108,8 +114,8 @@ private:
// from a worker thread after privileges have been dropped.
class HttpProxyServer {
public:
    // idleTimeoutSeconds: see HttpProxyController's own doc comment above -- threaded down
    // into the controller it constructs internally in run().
    // idleTimeoutSeconds/upstreamTimeoutSeconds: see HttpProxyController's own doc comment
    // above -- threaded down into the controller it constructs internally in run().
    HttpProxyServer(config::ListenerConfig listener,
                     std::string certPath,
                     std::string keyPath,
@@ -119,7 +125,8 @@ public:
                     lb::LoadBalancer &loadBalancer,
                     http::UpstreamConnectionPool &connectionPool,
                     tls::AcmeChallengeStore *acmeChallenges = nullptr,
                     int idleTimeoutSeconds = 0);
                     int idleTimeoutSeconds = 0,
                     int upstreamTimeoutSeconds = 60);

    // SNI virtual hosting variant: certsByHostname carries one CertificateBundle per domain
    // sharing this listener (see ListenerConfig::tlsProfiles) instead of the single cert/key
@@ -132,7 +139,8 @@ public:
                     lb::LoadBalancer &loadBalancer,
                     http::UpstreamConnectionPool &connectionPool,
                     tls::AcmeChallengeStore *acmeChallenges = nullptr,
                     int idleTimeoutSeconds = 0);
                     int idleTimeoutSeconds = 0,
                     int upstreamTimeoutSeconds = 60);

    void run();

@@ -161,6 +169,7 @@ private:
    http::UpstreamConnectionPool &_connectionPool;
    tls::AcmeChallengeStore *_acmeChallenges;
    int _idleTimeoutSeconds;
    int _upstreamTimeoutSeconds;
};

} // namespace proxyplus::httpproxy
Loading