{"record":{"id":"a7b8bba2b3ff96d0","repo":"hibiken/asynq","slug":"redis-connection-is-shared-so-the-inspector-can-t","errorCode":null,"errorMessage":"redis connection is shared so the Inspector can't be closed through asynq","messagePattern":"redis connection is shared so the Inspector can't be closed through asynq","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"inspector.go","lineNumber":52,"sourceCode":"\t}\n\tinspector := NewInspectorFromRedisClient(c)\n\tinspector.sharedConnection = false\n\treturn inspector\n}\n\n// NewInspectorFromRedisClient returns a new instance of Inspector given a redis.UniversalClient\n// Warning: The underlying redis connection pool will not be closed by Asynq, you are responsible for closing it.\nfunc NewInspectorFromRedisClient(c redis.UniversalClient) *Inspector {\n\treturn &Inspector{\n\t\trdb:              rdb.NewRDB(c),\n\t\tsharedConnection: true,\n\t}\n}\n\n// Close closes the connection with redis.\nfunc (i *Inspector) Close() error {\n\tif i.sharedConnection {\n\t\treturn fmt.Errorf(\"redis connection is shared so the Inspector can't be closed through asynq\")\n\t}\n\treturn i.rdb.Close()\n}\n\n// Queues returns a list of all queue names.\nfunc (i *Inspector) Queues() ([]string, error) {\n\treturn i.rdb.AllQueues()\n}\n\n// Groups returns a list of all groups within the given queue.\nfunc (i *Inspector) Groups(queue string) ([]*GroupInfo, error) {\n\tstats, err := i.rdb.GroupStats(queue)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar res []*GroupInfo\n\tfor _, s := range stats {\n\t\tres = append(res, &GroupInfo{","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/inspector.go#L34-L70","documentation":"Inspector.Close refuses to close a Redis connection that the Inspector shares with another client (created via NewInspectorFromRedisClient or similar sharing constructors). Closing the shared connection would break the other asynq components using it, so the library returns this error instead of closing. The caller owns the connection in that case and must close it themselves.","triggerScenarios":"Calling Inspector.Close() on an Inspector constructed from a shared redis.UniversalClient — e.g. tests or apps that pass one redis client to both asynq.Client and asynq.NewInspectorFromRedisClient, then call inspector.Close().","commonSituations":"Sharing a single redis.Client across Client, Scheduler, and Inspector for connection pooling; test cleanup/deferred Close on a shared-connection Inspector; embedding the Inspector in a service that closes all resources on shutdown.","solutions":["Track connection ownership yourself: call Close on the original redis client you passed in, not on the shared Inspector.","Construct the Inspector with its own connection (asynq.NewInspector(redisAddr)) if you need Inspector.Close to work.","Guard shutdown code: skip inspector.Close() when the Inspector was built from a shared client.","Log and ignore this specific error during teardown if closing the shared connection elsewhere."],"exampleFix":"// before\ninspector := asynq.NewInspectorFromRedisClient(rdb)\ndefer inspector.Close() // errors: connection is shared\n// after\ninspector := asynq.NewInspectorFromRedisClient(rdb)\ndefer func() {\n    if err := inspector.Close(); err != nil {\n        log.Println(\"inspector uses shared connection; closing owner rdb instead\")\n    }\n    rdb.Close()\n}()","handlingStrategy":"try-catch","validationCode":"// track how the inspector was created\nfunc closableInspector(shared bool, i *asynq.Inspector) bool { return !shared }","typeGuard":null,"tryCatchPattern":"if err := inspector.Close(); err != nil && strings.Contains(err.Error(), \"connection is shared\") {\n    // close the owning redis client instead\n    rdb.Close()\n}","preventionTips":["Track ownership of the redis client passed to NewInspectorFromRedisClient.","Use defer on the original client, not the shared Inspector, for cleanup.","Create a dedicated Inspector if you rely on Close().","During shutdown, close each component in the order you created them."],"tags":["go","asynq","redis","connection-lifecycle"],"backgroundTag":"unsupported-operation","analyzedSha":"d135f1439bee74e989b7f9b41ecd542cc87f024a","analyzedAt":"2026-09-07T19:02:34.660Z","contentChangedAt":"2026-09-07T19:02:34.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}