fix: prevent reverse affinity index from premature expiration

The reverse index account_affinity:{accountID} was using the same 1h
EXPIRE as the forward index. But the forward key EXPIRE refreshes on
every client request, while the reverse key only refreshes when a
request is routed to that specific account. This caused reverse keys
to expire prematurely.

Fix: set reverse key EXPIRE to 24h as safety net, rely on
ZREMRANGEBYSCORE for member-level expiration. Also clean up empty
keys after member cleanup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
erio
2026-03-06 18:04:52 +08:00
co-authored by Claude Opus 4.6
parent c7e88ffcf1
commit 6315dea094
2 changed files with 8 additions and 4 deletions
+1 -1
View File
@@ -1 +1 @@
0.1.92.5
0.1.92.6
+7 -3
View File
@@ -86,7 +86,7 @@ redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[4])
redis.call('ZADD', KEYS[1], ARGV[1], ARGV[3])
redis.call('EXPIRE', KEYS[1], ARGV[2])
redis.call('ZADD', KEYS[2], ARGV[1], ARGV[5])
redis.call('EXPIRE', KEYS[2], ARGV[2])
redis.call('EXPIRE', KEYS[2], 86400)
return 1
`)
@@ -144,12 +144,16 @@ func buildAccountAffinityKey(accountID int64) string {
return fmt.Sprintf("%s%d", accountAffinityPrefix, accountID)
}
// getAccountAffinityScript: 清理过期成员后返回 ZCARD
// getAccountAffinityScript: 清理过期成员后返回 ZCARD,空 key 自动删除
// KEYS[1] = account_affinity:{accountID}
// ARGV[1] = 过期阈值时间戳 (now - ttl)
var getAccountAffinityScript = redis.NewScript(`
redis.call('ZREMRANGEBYSCORE', KEYS[1], '-inf', ARGV[1])
return redis.call('ZCARD', KEYS[1])
local count = redis.call('ZCARD', KEYS[1])
if count == 0 then
redis.call('DEL', KEYS[1])
end
return count
`)
func (c *gatewayCache) GetAccountAffinityCount(ctx context.Context, accountID int64, ttl time.Duration) (int, error) {