From 231054c1720f7a2d166e5e0d69ef7f8999697482 Mon Sep 17 00:00:00 2001 From: mlsmaycon Date: Fri, 4 Sep 2026 04:04:56 +0200 Subject: [PATCH] [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. --- client/embed/embed.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/embed/embed.go b/client/embed/embed.go index 32e567be4..543ec9561 100644 --- a/client/embed/embed.go +++ b/client/embed/embed.go @@ -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)