问题:旧方案使用计数器模式,每次acquire都刷新TTL,导致僵尸数据永不过期
解决方案:
- 每个槽位使用独立Redis Key: concurrency:account:{id}:{requestID}
- 利用Redis原生TTL,每个槽位独立5分钟过期
- 服务崩溃后僵尸数据自动清理,无需手动干预
- 兼容多实例K8s部署
技术改动:
- 新增SCAN脚本统计活跃槽位数量
- 移除冗余的releaseScript,直接使用DEL命令
- Wait队列TTL只在首次创建时设置,避免刷新
24 lines
1.2 KiB
Go
24 lines
1.2 KiB
Go
package ports
|
|
|
|
import "context"
|
|
|
|
// ConcurrencyCache defines cache operations for concurrency service
|
|
// Uses independent keys per request slot with native Redis TTL for automatic cleanup
|
|
type ConcurrencyCache interface {
|
|
// Account slot management - each slot is a separate key with independent TTL
|
|
// Key format: concurrency:account:{accountID}:{requestID}
|
|
AcquireAccountSlot(ctx context.Context, accountID int64, maxConcurrency int, requestID string) (bool, error)
|
|
ReleaseAccountSlot(ctx context.Context, accountID int64, requestID string) error
|
|
GetAccountConcurrency(ctx context.Context, accountID int64) (int, error)
|
|
|
|
// User slot management - each slot is a separate key with independent TTL
|
|
// Key format: concurrency:user:{userID}:{requestID}
|
|
AcquireUserSlot(ctx context.Context, userID int64, maxConcurrency int, requestID string) (bool, error)
|
|
ReleaseUserSlot(ctx context.Context, userID int64, requestID string) error
|
|
GetUserConcurrency(ctx context.Context, userID int64) (int, error)
|
|
|
|
// Wait queue - uses counter with TTL set only on creation
|
|
IncrementWaitCount(ctx context.Context, userID int64, maxWait int) (bool, error)
|
|
DecrementWaitCount(ctx context.Context, userID int64) error
|
|
}
|