[client] Honor the start context while the embedded client authenticates

Start took a start context but ran auth.NewAuth and Login on a context derived
from Background, so the timeout only began to apply once authentication had
already returned. Both calls retry, and a management endpoint that accepts
connections but never completes a stream gives them nothing of their own to
time out against, so a client could sit in startup indefinitely with the
caller's deadline ignored.

A process running many clients behind a bounded start concurrency loses more
than one client to this: the stalled starts hold every slot, and the rest never
launch at all. Observed with 50 clients against a rate-limiting endpoint, where
seven came up, ten held the slots, and the remaining thirty-three never
started.

Neither call outlives startup, so moving them onto startCtx changes nothing
about the running client's lifetime.
This commit is contained in:
mlsmaycon
2026-09-04 04:04:56 +02:00
parent 6097296f77
commit 231054c172
+7 -2
View File
@@ -300,13 +300,18 @@ func (c *Client) Start(startCtx context.Context) error {
// nolint:staticcheck
ctx = context.WithValue(ctx, system.DeviceNameCtxKey, c.deviceName)
authClient, err := auth.NewAuth(ctx, c.config.PrivateKey, c.config.ManagementURL, c.config)
// Authentication runs on startCtx, not the client's own context. Both
// calls retry, and a management endpoint that accepts connections but
// never completes a stream leaves them retrying with no deadline of their
// own, so a caller's start timeout has to reach them. Neither outlives
// startup: authClient is closed below.
authClient, err := auth.NewAuth(startCtx, c.config.PrivateKey, c.config.ManagementURL, c.config)
if err != nil {
return fmt.Errorf("create auth client: %w", err)
}
defer authClient.Close()
if err, _ := authClient.Login(ctx, c.setupKey, c.jwtToken); err != nil {
if err, _ := authClient.Login(startCtx, c.setupKey, c.jwtToken); err != nil {
return fmt.Errorf("login: %w", err)
}
client := internal.NewConnectClient(ctx, c.config, c.recorder)