{"record":{"id":"13ba4eb1a28b9728","repo":"micro/go-micro","slug":"unable-to-close-in-time","errorCode":null,"errorMessage":"unable to close in time","messagePattern":"unable to close in time","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/util/pool/default.go","lineNumber":154,"sourceCode":"\t\treturn conn.(*poolConn).close()\n\t}\n\n\tp.conns[conn.Remote()] = append(conns, conn.(*poolConn))\n\n\treturn nil\n}\n\nfunc (p *poolConn) close() error {\n\tch := make(chan error)\n\tgo func() {\n\t\tdefer close(ch)\n\t\tch <- p.Client.Close()\n\t}()\n\tt := time.NewTimer(p.closeTimeout)\n\tvar err error\n\tselect {\n\tcase <-t.C:\n\t\terr = errors.New(\"unable to close in time\")\n\tcase err = <-ch:\n\t\tt.Stop()\n\t}\n\treturn err\n}\n","sourceCodeStart":136,"sourceCodeEnd":160,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/internal/util/pool/default.go#L136-L160","documentation":"pool.close in internal/util/pool/default.go closes a pooled client asynchronously and waits up to p.closeTimeout for the Close call to finish. If the timer fires before Close returns, the pool gives up and returns this error. It means the underlying client hung during shutdown.","triggerScenarios":"Calling pool.Close() (or letting a pool be torn down) when an underlying gRPC/client connection cannot close promptly — e.g. in-flight RPCs, a blocked transport, or a server that never responds to connection teardown.","commonSituations":"Test cleanup where a fake server never closes connections; production shutdown with live streaming RPCs; network partitions making the client's close handshake block until TCP timeouts.","solutions":["Increase the pool's closeTimeout option so slow-but-healthy clients have time to close.","Ensure all in-flight calls/streaming RPCs are completed or cancelled before closing the pool.","Check that the backend the client connects to is reachable and honoring connection close.","Investigate the client's Close path for hangs (e.g. dial retries or un-drained streams) and fix the root cause."],"exampleFix":"// before\npool, err := pool.NewPool(pool.CloseTimeout(500*time.Millisecond))\n// after\npool, err := pool.NewPool(pool.CloseTimeout(5*time.Second))","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"if err := p.Close(); err != nil {\n    if strings.Contains(err.Error(), \"unable to close in time\") {\n        log.Warn(\"pool close timed out; client may still be draining\", \"timeout\", p.closeTimeout)\n        // proceed with shutdown; don't fail the whole process\n        return nil\n    }\n    return err\n}","preventionTips":["Set a generous closeTimeout for production pools","Cancel in-flight RPCs/streams before closing the pool","Ensure backends are reachable and respond to connection close","Monitor for hung Close calls and alert on repeated timeouts"],"tags":["timeout","connection-lifecycle","grpc","shutdown"],"backgroundTag":"connection-close-timeout","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}