Skip to content

Commit 7df261c

Browse files
feat: make the backend dial timeout configurable (--backend-dial-timeout) (#570)
Follow-up to #569: replace the fixed 2s backendDialTimeout constant with a --backend-dial-timeout flag (env BACKEND_DIAL_TIMEOUT), defaulting to the same 2s. Operators whose backends are reachable quickly (e.g. on-cluster Kubernetes Services) can lower it so the asleep MOTD / scale-up fallback fires sooner on a scaled-to-zero backend. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 97b15df commit 7df261c

4 files changed

Lines changed: 22 additions & 2 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ Some other features included:
4444
If set, statically-configured backends are scaled up on access and down after idle by POSTing to this URL (env AUTO_SCALE_WEBHOOK_URL)
4545
-auto-scale-webhook-wake-timeout duration
4646
Maximum time to wait for the backend to become reachable after a scale-up webhook (env AUTO_SCALE_WEBHOOK_WAKE_TIMEOUT) (default 1m0s)
47+
-backend-dial-timeout duration
48+
Timeout for establishing the TCP connection to a backend. Bounds how long a dial to a scaled-to-zero server's Service (no endpoints) waits before the auto-scale asleep MOTD / scale-up fallback is served; operators with fast on-cluster backends can lower it so that fallback fires sooner (env BACKEND_DIAL_TIMEOUT) (default 2s)
4749
-clients-to-allow value
4850
Zero or more client IP addresses or CIDRs to allow. Takes precedence over deny. (env CLIENTS_TO_ALLOW)
4951
-clients-to-deny value

server/configs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type Config struct {
4646
ApiBinding string `usage:"The [host:port] bound for servicing API requests"`
4747
CpuProfile string `usage:"Enables CPU profiling and writes to given path"`
4848
ConnectionRateLimit int `default:"1" usage:"Max number of connections to allow per second"`
49+
BackendDialTimeout time.Duration `default:"2s" usage:"Timeout for establishing the TCP connection to a backend. Bounds how long a dial to a scaled-to-zero server's Service (no endpoints) waits before the auto-scale asleep MOTD / scale-up fallback is served; operators with fast on-cluster backends can lower it so that fallback fires sooner"`
4950
InKubeCluster bool `usage:"Use in-cluster Kubernetes config"`
5051
KubeConfig string `usage:"The path to a Kubernetes configuration file"`
5152
KubeNamespace string `usage:"The namespace to watch or blank for all, which is the default"`

server/connector.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ const (
3030
// before the auto-scale asleep MOTD is served from the dial-failure
3131
// fallback below. A healthy backend accepts the TCP connection almost
3232
// instantly, so this bound only trips on unreachable/asleep backends.
33-
backendDialTimeout = 2 * time.Second
33+
// Overridable via --backend-dial-timeout: operators whose backends are
34+
// reachable faster (e.g. on-cluster Services) can lower it so the asleep
35+
// MOTD / scale-up fallback fires sooner.
36+
defaultBackendDialTimeout = 2 * time.Second
3437
)
3538

3639
var noDeadline time.Time
@@ -89,6 +92,18 @@ func NewConnector(ctx context.Context, routes IRoutes, downScaler IDownScaler, m
8992
activeConnections: NewActiveConnections(),
9093
scaleActiveConnections: NewActiveConnections(),
9194
wakingServers: NewActiveConnections(),
95+
backendDialTimeout: defaultBackendDialTimeout,
96+
}
97+
}
98+
99+
// UseBackendDialTimeout overrides the timeout for establishing the TCP
100+
// connection to a backend (values <= 0 keep the default). Backends that are
101+
// reachable quickly — e.g. on-cluster Services — can use a shorter timeout so
102+
// the asleep-MOTD / scale-up fallback fires promptly on a scaled-to-zero
103+
// backend instead of waiting the full default.
104+
func (c *Connector) UseBackendDialTimeout(d time.Duration) {
105+
if d > 0 {
106+
c.backendDialTimeout = d
92107
}
93108
}
94109

@@ -118,6 +133,7 @@ type Connector struct {
118133
connectionNotifier ConnectionNotifier
119134
asleepMOTD string
120135
loadingMOTD string
136+
backendDialTimeout time.Duration
121137
}
122138

123139
func (c *Connector) UseConnectionNotifier(notifier ConnectionNotifier) {
@@ -655,7 +671,7 @@ func (c *Connector) findAndConnectBackend(frontendConn net.Conn,
655671
Info("Connecting to backend")
656672

657673
//goland:noinspection GoResourceLeak ownership transferred to pumpConnections and closed with return statements below
658-
backendConn, err := net.DialTimeout("tcp", backendHostPort, backendDialTimeout)
674+
backendConn, err := net.DialTimeout("tcp", backendHostPort, c.backendDialTimeout)
659675
if err != nil {
660676
logrus.
661677
WithError(err).

server/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func NewServer(ctx context.Context, config *Config) (*Server, error) {
104104

105105
connector := NewConnector(ctx, routes, downscaler, metricsBuilder.BuildConnectorMetrics(), config.UseProxyProtocol, config.RecordLogins, autoScaleAllowDenyConfig)
106106

107+
connector.UseBackendDialTimeout(config.BackendDialTimeout)
107108
connector.UseAsleepMOTD(config.AutoScale.AsleepMOTD)
108109
connector.UseLoadingMOTD(config.AutoScale.LoadingMOTD)
109110

0 commit comments

Comments
 (0)