{"record":{"id":"14be04cdd0ac83e8","repo":"openimsdk/open-im-server","slug":"listener-done","errorCode":null,"errorMessage":"listener done","messagePattern":"listener done","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/common/startrpc/start.go","lineNumber":200,"sourceCode":"\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tlog.ZDebug(ctx, \"prometheus start\", \"addr\", prometheusListener.Addr(), \"rpcRegisterName\", rpcRegisterName)\n\t\ttarget, err := jsonutil.JsonMarshal(prommetrics.BuildDefaultTarget(registerIP, prometheusPort))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif autoSetPorts {\n\t\t\tif err = client.SetWithLease(ctx, prommetrics.BuildDiscoveryKey(rpcRegisterName, index), target, prommetrics.TTL); err != nil {\n\t\t\t\tif !errors.Is(err, discovery.ErrNotSupported) {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tgo func() {\n\t\t\terr := prommetrics.Start(prometheusListener)\n\t\t\tif err == nil {\n\t\t\t\terr = fmt.Errorf(\"listener done\")\n\t\t\t}\n\t\t\tcancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))\n\t\t}()\n\t}\n\n\tvar (\n\t\trpcServer       *grpc.Server\n\t\trpcGracefulStop chan struct{}\n\t)\n\n\tonGrpcServiceRegistrar := func(desc *grpc.ServiceDesc, impl any) {\n\t\tif rpcServer != nil {\n\t\t\trpcServer.RegisterService(desc, impl)\n\t\t\treturn\n\t\t}\n\t\tvar rpcListenAddr string\n\t\tif autoSetPorts {\n\t\t\trpcListenAddr = net.JoinHostPort(listenIP, \"0\")","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/openimsdk/open-im-server/blob/175a7bb0673eca18e9d1b10bff4f728da6b1b513/pkg/common/startrpc/start.go#L182-L218","documentation":"The prometheus metrics server goroutine calls prommetrics.Start(listener); Start only returns an error. If it returns nil it means the serve loop ended without an error (listener closed / server returned), which is still fatal for metrics, so the code synthesizes 'listener done' as the error and cancels the root context with 'prommetrics <rpcName> listener done'.","triggerScenarios":"prommetrics.Start returns nil — the prometheus HTTP server stopped serving (listener closed, Serve returned) — or the goroutine otherwise reaches cancel with a nil error converted to 'listener done'.","commonSituations":"Another component closed the listener; the metrics HTTP handler panicked or was shut down; process teardown cancelling the listener; port listener unexpectedly closed by the OS.","solutions":["Check what closed the metrics listener — look for other code calling Close on prometheusListener or a shutdown path running concurrently.","Verify prometheusListenAddr isn't shared with another component that steals/closes the socket.","If metrics are optional, wrap this cancel so a metrics failure doesn't kill the whole RPC server.","Inspect prommetrics.Start implementation to understand when it returns nil vs error (e.g. http.Serve returning http.ErrServerClosed)."],"exampleFix":"// before\nerr := prommetrics.Start(prometheusListener)\nif err == nil {\n    err = fmt.Errorf(\"listener done\")\n}\ncancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))\n// after\nerr := prommetrics.Start(prometheusListener)\nif errors.Is(err, http.ErrServerClosed) {\n    return\n}\ncancel(fmt.Errorf(\"prommetrics %s %w\", rpcRegisterName, err))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if cause := context.Cause(ctx); cause != nil && strings.Contains(cause.Error(), \"listener done\") {\n    log.Warn(\"prometheus metrics server exited silently\", \"rpc\", rpcRegisterName)\n}","preventionTips":["Don't share the metrics listener address with other components","Treat http.ErrServerClosed as normal teardown, not failure","Consider making metrics failure non-fatal (log instead of cancel)"],"tags":["prometheus","metrics","lifecycle"],"backgroundTag":"metrics-server-exited","analyzedSha":"175a7bb0673eca18e9d1b10bff4f728da6b1b513","analyzedAt":"2026-09-04T16:52:56.821Z","contentChangedAt":"2026-09-04T16:52:56.821Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}