90 lines
2.8 KiB
Go
90 lines
2.8 KiB
Go
package redisdao
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/global"
|
|
"git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/redismodel"
|
|
"github.com/redis/go-redis/v9"
|
|
)
|
|
|
|
// notificationUnreadTTL 未读数 key 的过期时间,避免长期驻留与 MySQL 弱一致漂移。
|
|
const notificationUnreadTTL = 7 * 24 * time.Hour
|
|
|
|
// notificationUnreadIncrScript 首次自增时设置过期时间,保证 INCR 与 EXPIRE 原子执行。
|
|
var notificationUnreadIncrScript = redis.NewScript(`
|
|
local v = redis.call('INCR', KEYS[1])
|
|
if v == 1 then
|
|
redis.call('EXPIRE', KEYS[1], ARGV[1])
|
|
end
|
|
return v
|
|
`)
|
|
|
|
// notificationUnreadDecrScript 未读数 -1,保证结果不低于 0
|
|
var notificationUnreadDecrScript = redis.NewScript(`
|
|
local v = redis.call('GET', KEYS[1])
|
|
if v and tonumber(v) > 0 then
|
|
return redis.call('DECRBY', KEYS[1], 1)
|
|
end
|
|
return 0
|
|
`)
|
|
|
|
// NotificationUnreadIncr 用户未读消息数 +1,返回最新值
|
|
func NotificationUnreadIncr(ctx context.Context, userID int64) (int64, error) {
|
|
ctx, span := global.Tracer.Start(ctx, "redisdao.NotificationUnreadIncr")
|
|
defer span.End()
|
|
|
|
key := fmt.Sprintf(redismodel.KeyNotificationUnread, userID)
|
|
val, err := notificationUnreadIncrScript.Run(ctx, global.RedisEngine, []string{key}, int(notificationUnreadTTL.Seconds())).Int64()
|
|
if err != nil {
|
|
span.RecordError(err)
|
|
return 0, err
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
// NotificationUnreadDecr 用户未读消息数 -1,返回扣减后的值(不低于 0)
|
|
func NotificationUnreadDecr(ctx context.Context, userID int64) (int64, error) {
|
|
ctx, span := global.Tracer.Start(ctx, "redisdao.NotificationUnreadDecr")
|
|
defer span.End()
|
|
|
|
key := fmt.Sprintf(redismodel.KeyNotificationUnread, userID)
|
|
val, err := notificationUnreadDecrScript.Run(ctx, global.RedisEngine, []string{key}).Int64()
|
|
if err != nil {
|
|
span.RecordError(err)
|
|
return 0, err
|
|
}
|
|
return val, nil
|
|
}
|
|
|
|
// NotificationUnreadGet 获取用户未读消息数,不存在时返回 0
|
|
func NotificationUnreadGet(ctx context.Context, userID int64) (int64, error) {
|
|
ctx, span := global.Tracer.Start(ctx, "redisdao.NotificationUnreadGet")
|
|
defer span.End()
|
|
|
|
key := fmt.Sprintf(redismodel.KeyNotificationUnread, userID)
|
|
v, err := global.RedisEngine.Get(ctx, key).Int64()
|
|
if err == redis.Nil {
|
|
return 0, nil
|
|
}
|
|
if err != nil {
|
|
span.RecordError(err)
|
|
}
|
|
return v, err
|
|
}
|
|
|
|
// NotificationUnreadSet 回填未读数缓存(DB 对账回源后使用),避免 key 过期导致后续扣减被吞。
|
|
func NotificationUnreadSet(ctx context.Context, userID int64, cnt int64) error {
|
|
ctx, span := global.Tracer.Start(ctx, "redisdao.NotificationUnreadSet")
|
|
defer span.End()
|
|
|
|
key := fmt.Sprintf(redismodel.KeyNotificationUnread, userID)
|
|
if err := global.RedisEngine.Set(ctx, key, cnt, notificationUnreadTTL).Err(); err != nil {
|
|
span.RecordError(err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|