0

Add cancellable context for Redis operation to prevent hanging redis ops on shutdown

- Rename Ctx to RedisCtx with CancelRedisCtx function
- Signal handler now cancels context before closing Redis
This commit is contained in:
eleksir
2026-03-30 16:34:18 +03:00
parent 57b2c56b3f
commit 59643b6a0a
3 changed files with 18 additions and 7 deletions

View File

@@ -40,11 +40,11 @@ func main() {
MaxRetries: -1,
MinRetryBackoff: time.Second,
MaxRetryBackoff: 30 * time.Second,
}).WithContext(misc.Ctx).WithTimeout(time.Duration(misc.Config.Timeout) * time.Second)
}).WithContext(misc.RedisCtx).WithTimeout(time.Duration(misc.Config.Timeout) * time.Second)
// Проверим, что редиска доступна. Повторяем попытки, пока не подключится.
for {
if err := misc.RedisClient.Ping(misc.Ctx).Err(); err == nil {
if err := misc.RedisClient.Ping(misc.RedisCtx).Err(); err == nil {
break
}
@@ -53,7 +53,7 @@ func main() {
}
// Обозначим, что хотим после соединения подписаться на события из канала config.Channel.
misc.Subscriber = misc.RedisClient.Subscribe(misc.Ctx, misc.Config.Channel)
misc.Subscriber = misc.RedisClient.Subscribe(misc.RedisCtx, misc.Config.Channel)
// Самое время поставить траппер сигналов.
signal.Notify(misc.SigChan,
@@ -69,7 +69,7 @@ func main() {
log.Info("Aleesa-misc-go started")
for msg := range ch {
misc.MsgParser(misc.Ctx, msg.Payload)
misc.MsgParser(misc.RedisCtx, msg.Payload)
}
}

View File

@@ -3,6 +3,7 @@ package misc
import (
"context"
"os"
"sync"
"github.com/go-redis/redis/v8"
)
@@ -20,7 +21,14 @@ var Subscriber *redis.PubSub
// Канал, в который приходят уведомления для хэндлера сигналов от траппера сигналов.
var SigChan = make(chan os.Signal, 1)
// Main context.
var Ctx = context.Background()
// RedisCtx - контекст для операций с редиской. Отменяется при завершении.
var RedisCtx context.Context
var CancelRedisCtx context.CancelFunc
var once sync.Once
func init() {
RedisCtx, CancelRedisCtx = context.WithCancel(context.Background())
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

View File

@@ -28,8 +28,11 @@ func SigHandler() {
continue
}
// Отменяем контекст редиски, чтобы все ожидающие операции завершились.
CancelRedisCtx()
// Отпишемся от всех каналов и закроем коннект к редиске.
if err = Subscriber.Unsubscribe(Ctx); err != nil {
if err = Subscriber.Unsubscribe(RedisCtx); err != nil {
log.Errorf("Unable to unsubscribe from redis channels cleanly: %s", err)
}