{"record":{"id":"3cd5d0bbef1e4a72","repo":"vitessio/vitess","slug":"v-v","errorCode":null,"errorMessage":"%v: %v","messagePattern":"%v: %v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/mysqlctl/grpcmysqlctlclient/client.go","lineNumber":154,"sourceCode":"\t\tversion = r.Version\n\t\treturn nil\n\t})\n\treturn version, err\n}\n\n// Close is part of the MysqlctlClient interface.\nfunc (c *client) Close() {\n\tc.cc.Close()\n}\n\n// withRetry is needed because grpc doesn't handle some transient errors\n// correctly (like EAGAIN) when sockets are used.\nfunc (c *client) withRetry(ctx context.Context, f func() error) error {\n\tvar lastError error\n\tfor {\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn fmt.Errorf(\"%v: %v\", ctx.Err(), lastError)\n\t\tdefault:\n\t\t}\n\t\tif err := f(); err != nil {\n\t\t\tif st, ok := status.FromError(err); ok {\n\t\t\t\tcode := st.Code()\n\t\t\t\tif code == codes.Unavailable {\n\t\t\t\t\tlastError = err\n\t\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n\nfunc init() {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/mysqlctl/grpcmysqlctlclient/client.go#L136-L172","documentation":"withRetry loops an RPC until success or context expiry; when ctx.Done() fires it returns a combined error of the context's error (e.g. context deadline exceeded / canceled) plus the last RPC error seen, so both the timeout and the underlying failure are visible.","triggerScenarios":"Calling any mysqlctl client RPC (Start, Shutdown, RunMysqlUpgrade, ApplyBinlogFile, ReadBinlogFilesTimestamps, ReinitConfig) whose retries exhaust past the caller's context deadline or get canceled.","commonSituations":"mysqlctl server down or slow so every attempt returns Unavailable and retries burn the whole deadline; caller-set context timeout too short for long operations like MysqlUpgrade; task cancellation during shutdown.","solutions":["Increase the context deadline for long-running mysqlctl operations.","Verify the mysqlctl server is reachable and healthy (reduces Unavailable retries).","Inspect lastError in the combined message for the root RPC failure (e.g. connection refused)."],"exampleFix":"// before\nctx := context.Background(); defer cancel() // no timeout\n// after\nctx, cancel := context.WithTimeout(t.Context(), 10*time.Minute)\ndefer cancel()","handlingStrategy":"try-catch","validationCode":"// pre-check reachability before long RPC\nconn, err := net.DialTimeout(\"tcp\", addr, 2*time.Second)\nif err != nil { return fmt.Errorf(\"mysqlctl unreachable at %s\", addr) }\nconn.Close()","typeGuard":null,"tryCatchPattern":"err := client.Start(ctx, ...)\nif err != nil {\n\tif strings.Contains(err.Error(), context.DeadlineExceeded.Error()) {\n\t\t// increase deadline / check server health\n\t}\n\treturn err\n}","preventionTips":["Size context timeouts to the operation (MysqlUpgrade needs minutes, not seconds)","Alert on mysqlctl server availability; unhealthy servers burn retry budgets","Log ctx.Err() and lastError separately in wrappers for diagnosis"],"tags":["grpc","timeout","retry","context"],"backgroundTag":"context-deadline-exceeded","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}