fix: Redis集群SCAN遍历所有master节点 + 查询结果布局调整\n\n1. ScanAllKeys(): 集群模式用ForEachMaster遍历所有master节点SCAN合并去重\n2. RedisScanKeys/KEYS命令均改用ScanAllKeys,确保集群不遗漏key\n3. QueriesPage布局: sidebar独立左侧,查询结果只在编辑器下方不被sidebar占据宽度
This commit is contained in:
1 parent
430a667455
commit
4e6f9eb8fd
3 files changed
+97
-61
No files matched your search
@@ -59,6 +59,53 @@ func (w *redisClientWrapper) Scan(ctx context.Context, cursor uint64, match stri
|
||||
return w.Client.Scan(ctx, cursor, match, count)
|
||||
}
|
||||
|
||||
// ScanAllKeys scans keys across ALL master nodes in cluster mode, or single node in standalone.
|
||||
// Returns merged deduplicated keys.
|
||||
func (w *redisClientWrapper) ScanAllKeys(ctx context.Context, match string, count int) ([]string, error) {
|
||||
if !w.isCluster {
|
||||
// Standalone: iterate SCAN until cursor returns to 0
|
||||
var allKeys []string
|
||||
cursor := uint64(0)
|
||||
for {
|
||||
keys, nextCursor, err := w.Client.Scan(ctx, cursor, match, int64(count)).Result()
|
||||
if err != nil {
|
||||
return allKeys, err
|
||||
}
|
||||
allKeys = append(allKeys, keys...)
|
||||
cursor = nextCursor
|
||||
if cursor == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return allKeys, nil
|
||||
}
|
||||
|
||||
// Cluster: iterate SCAN on every master node
|
||||
var allKeys []string
|
||||
seen := make(map[string]bool)
|
||||
err := w.ClusterClient.ForEachMaster(ctx, func(ctx context.Context, node *redis.Client) error {
|
||||
cursor := uint64(0)
|
||||
for {
|
||||
keys, nextCursor, err := node.Scan(ctx, cursor, match, int64(count)).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, k := range keys {
|
||||
if !seen[k] {
|
||||
seen[k] = true
|
||||
allKeys = append(allKeys, k)
|
||||
}
|
||||
}
|
||||
cursor = nextCursor
|
||||
if cursor == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return allKeys, err
|
||||
}
|
||||
|
||||
func (w *redisClientWrapper) Type(ctx context.Context, key string) *redis.StatusCmd {
|
||||
if w.isCluster {
|
||||
return w.ClusterClient.Type(ctx, key)
|
||||
@@ -321,7 +368,6 @@ func RedisScanKeys(c *gin.Context) {
|
||||
pattern = pattern + "*"
|
||||
}
|
||||
count, _ := strconv.Atoi(c.DefaultQuery("count", "100"))
|
||||
cursorParam := c.DefaultQuery("cursor", "0")
|
||||
|
||||
db := 0
|
||||
if dbParam != "" {
|
||||
@@ -342,8 +388,7 @@ func RedisScanKeys(c *gin.Context) {
|
||||
defer client.Close()
|
||||
|
||||
ctx := context.Background()
|
||||
cursor, _ := strconv.ParseUint(cursorParam, 10, 64)
|
||||
keys, nextCursor, err := client.Scan(ctx, cursor, pattern, int64(count)).Result()
|
||||
allKeys, err := client.ScanAllKeys(ctx, pattern, count)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"detail": err.Error()})
|
||||
return
|
||||
@@ -356,7 +401,7 @@ func RedisScanKeys(c *gin.Context) {
|
||||
TTL int64 `json:"ttl"`
|
||||
}
|
||||
var keyInfos []KeyInfo
|
||||
for _, key := range keys {
|
||||
for _, key := range allKeys {
|
||||
keyType, _ := client.Type(ctx, key).Result()
|
||||
ttl, _ := client.TTL(ctx, key).Result()
|
||||
ttlMs := int64(-1)
|
||||
@@ -371,7 +416,7 @@ func RedisScanKeys(c *gin.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"keys": keyInfos,
|
||||
"cursor": nextCursor,
|
||||
"cursor": 0,
|
||||
"total": len(keyInfos),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user