Add per-host connection limits for upstream fetching

- Add upstream_connections_per_host config option (default: 20)
- Implement per-host semaphores to limit concurrent connections
- Semaphore released when response body is closed
- Prevents overwhelming origin servers with parallel requests
This commit is contained in:
2026-01-08 05:19:20 -08:00
parent 49ff72dfa8
commit f244d9c7e0
4 changed files with 90 additions and 32 deletions

View File

@@ -16,8 +16,9 @@ import (
// Default configuration values.
const (
DefaultPort = 8080
DefaultStateDir = "./data"
DefaultPort = 8080
DefaultStateDir = "./data"
DefaultUpstreamConnectionsPerHost = 20
)
// Params defines dependencies for Config.
@@ -39,9 +40,10 @@ type Config struct {
DBURL string
// Image proxy settings
SigningKey string // HMAC signing key for URL signatures
WhitelistHosts []string // Hosts that don't require signatures
AllowHTTP bool // Allow non-TLS upstream (testing only)
SigningKey string // HMAC signing key for URL signatures
WhitelistHosts []string // Hosts that don't require signatures
AllowHTTP bool // Allow non-TLS upstream (testing only)
UpstreamConnectionsPerHost int // Max concurrent connections per upstream host
}
// New creates a new Config instance by loading configuration from file.
@@ -59,16 +61,17 @@ func New(_ fx.Lifecycle, params Params) (*Config, error) {
}
c := &Config{
Debug: getBool(sc, "debug", false),
MaintenanceMode: getBool(sc, "maintenance_mode", false),
Port: getInt(sc, "port", DefaultPort),
StateDir: getString(sc, "state_dir", DefaultStateDir),
SentryDSN: getString(sc, "sentry_dsn", ""),
MetricsUsername: getString(sc, "metrics.username", ""),
MetricsPassword: getString(sc, "metrics.password", ""),
SigningKey: getString(sc, "signing_key", ""),
WhitelistHosts: getStringSlice(sc, "whitelist_hosts"),
AllowHTTP: getBool(sc, "allow_http", false),
Debug: getBool(sc, "debug", false),
MaintenanceMode: getBool(sc, "maintenance_mode", false),
Port: getInt(sc, "port", DefaultPort),
StateDir: getString(sc, "state_dir", DefaultStateDir),
SentryDSN: getString(sc, "sentry_dsn", ""),
MetricsUsername: getString(sc, "metrics.username", ""),
MetricsPassword: getString(sc, "metrics.password", ""),
SigningKey: getString(sc, "signing_key", ""),
WhitelistHosts: getStringSlice(sc, "whitelist_hosts"),
AllowHTTP: getBool(sc, "allow_http", false),
UpstreamConnectionsPerHost: getInt(sc, "upstream_connections_per_host", DefaultUpstreamConnectionsPerHost),
}
// Build DBURL from StateDir if not explicitly set