Observation
Each call to `rebuildAllMiddlewares` (config_webhook.go after a Docker label change or INI reload) re-resolves every job's webhooks via `WebhookManager.GetMiddlewares`, which calls `NewWebhook` per name. `NewWebhook` constructs a fresh `*http.Client` and `*http.Transport` (`middlewares/webhook.go:61-64`):
```go
return &Webhook{
Config: config,
Preset: preset,
PresetLoader: loader,
Client: &http.Client{
Timeout: config.Timeout,
Transport: TransportFactory(),
},
}, nil
```
The preset itself is cached via `PresetLoader`, but the HTTP client/transport are not. Each reconcile drops any keep-alive connections held by the previous client.
For realistic deployments (tens of jobs × ≤5 webhooks × occasional reconciles) this is microseconds and unmeasurable. Filed for visibility, not as a blocker.
When this matters
If reconciles become high-frequency (e.g., a future feature triggers `rebuildAllMiddlewares` per container event in a churn-heavy environment), tail latency on webhook delivery will rise because every reconcile starts fresh TCP/TLS handshakes.
Fix sketch
Move the `*http.Client` to a manager-scoped field on `WebhookManager`, keyed by `(config.Timeout, AllowedHosts)` or whatever inputs affect transport posture. Webhooks share a client; reconciles reuse keep-alives. The deprecated `PresetLoader` already does this for preset fetches (see #630), so the pattern is in-repo.
Scope
Pre-existing; observed during PR #671 performance review. Not a regression and not on a hot path today. File and forget unless reconcile frequency goes up.
Observation
Each call to `rebuildAllMiddlewares` (config_webhook.go after a Docker label change or INI reload) re-resolves every job's webhooks via `WebhookManager.GetMiddlewares`, which calls `NewWebhook` per name. `NewWebhook` constructs a fresh `*http.Client` and `*http.Transport` (`middlewares/webhook.go:61-64`):
```go
return &Webhook{
Config: config,
Preset: preset,
PresetLoader: loader,
Client: &http.Client{
Timeout: config.Timeout,
Transport: TransportFactory(),
},
}, nil
```
The preset itself is cached via `PresetLoader`, but the HTTP client/transport are not. Each reconcile drops any keep-alive connections held by the previous client.
For realistic deployments (tens of jobs × ≤5 webhooks × occasional reconciles) this is microseconds and unmeasurable. Filed for visibility, not as a blocker.
When this matters
If reconciles become high-frequency (e.g., a future feature triggers `rebuildAllMiddlewares` per container event in a churn-heavy environment), tail latency on webhook delivery will rise because every reconcile starts fresh TCP/TLS handshakes.
Fix sketch
Move the `*http.Client` to a manager-scoped field on `WebhookManager`, keyed by `(config.Timeout, AllowedHosts)` or whatever inputs affect transport posture. Webhooks share a client; reconciles reuse keep-alives. The deprecated `PresetLoader` already does this for preset fetches (see #630), so the pattern is in-repo.
Scope
Pre-existing; observed during PR #671 performance review. Not a regression and not on a hot path today. File and forget unless reconcile frequency goes up.