[GH-ISSUE #1095] [BUG] Memory leak: subscriber goroutine retries SUBSCRIBE infinitely without closing PubSub on failure #2549

Open
opened 2026-03-15 20:50:13 +03:00 by kerem · 2 comments
Owner

Originally created by @chaojidage on GitHub (Feb 24, 2026).
Original GitHub issue: https://github.com/hibiken/asynq/issues/1095

Originally assigned to: @hibiken, @kamikazechaser on GitHub.

Bug Description

When the Redis server does not support the SUBSCRIBE command (e.g., certain
managed Redis services or Redis proxies with PUB/SUB disabled), the subscriber
goroutine enters an infinite retry loop, and each retry leaks a Redis
connection
, causing memory to grow unboundedly.

Root Cause

There are two bugs working together:

Bug 1: Leaked connection in internal/rdb/rdb.go

In CancelationPubSub(), when pubsub.Receive() fails, the pubsub object is
returned as nil but is never closed, leaking the underlying Redis connection:

// internal/rdb/rdb.go
func (r *RDB) CancelationPubSub() (*redis.PubSub, error) {
pubsub := r.client.Subscribe(ctx, base.CancelChannel)
_, err := pubsub.Receive(ctx)
if err != nil {
// BUG: pubsub is never closed here, connection is leaked
return nil, errors.E(op, errors.Unknown, ...)
}
return pubsub, nil
}

Originally created by @chaojidage on GitHub (Feb 24, 2026). Original GitHub issue: https://github.com/hibiken/asynq/issues/1095 Originally assigned to: @hibiken, @kamikazechaser on GitHub. ## Bug Description When the Redis server does not support the `SUBSCRIBE` command (e.g., certain managed Redis services or Redis proxies with PUB/SUB disabled), the `subscriber` goroutine enters an **infinite retry loop**, and each retry **leaks a Redis connection**, causing memory to grow unboundedly. ## Root Cause There are two bugs working together: ### Bug 1: Leaked connection in `internal/rdb/rdb.go` In `CancelationPubSub()`, when `pubsub.Receive()` fails, the `pubsub` object is returned as `nil` but is **never closed**, leaking the underlying Redis connection: // internal/rdb/rdb.go func (r *RDB) CancelationPubSub() (*redis.PubSub, error) { pubsub := r.client.Subscribe(ctx, base.CancelChannel) _, err := pubsub.Receive(ctx) if err != nil { // BUG: pubsub is never closed here, connection is leaked return nil, errors.E(op, errors.Unknown, ...) } return pubsub, nil }
Author
Owner

@MengyuanWu1996 commented on GitHub (Feb 27, 2026):

We've also found this problem and are waiting for it to be fixed

<!-- gh-comment-id:3971928376 --> @MengyuanWu1996 commented on GitHub (Feb 27, 2026): We've also found this problem and are waiting for it to be fixed
Author
Owner

@chaojidage commented on GitHub (Feb 27, 2026):

We've also found this problem and are waiting for it to be fixed

中国人就尽量都说汉语哈哈哈,我们公司的 redis 不能使用 pub,sub 命令,我就发现被坑了

<!-- gh-comment-id:3971937272 --> @chaojidage commented on GitHub (Feb 27, 2026): > We've also found this problem and are waiting for it to be fixed 中国人就尽量都说汉语哈哈哈,我们公司的 redis 不能使用 pub,sub 命令,我就发现被坑了
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/asynq#2549
No description provided.