feat(redis): implement CSV parsing utility and refactor Redis transaction handling

This commit is contained in:
L1nSn0w
2026-04-20 15:29:36 +08:00
parent b46a20bd0f
commit 617e7a5f30
4 changed files with 68 additions and 22 deletions
+9 -17
View File
@@ -2,7 +2,6 @@ package plugin_manager
import (
"fmt"
"strings"
lru "github.com/hashicorp/golang-lru/v2"
"github.com/langgenius/dify-cloud-kit/oss"
@@ -18,6 +17,7 @@ import (
"github.com/langgenius/dify-plugin-daemon/pkg/plugin_packager/decoder"
"github.com/langgenius/dify-plugin-daemon/pkg/utils/cache"
"github.com/langgenius/dify-plugin-daemon/pkg/utils/log"
"github.com/langgenius/dify-plugin-daemon/pkg/utils/parser"
)
type PluginManager struct {
@@ -126,8 +126,14 @@ func (p *PluginManager) Launch(configuration *app.Config) {
cache.SetKeyPrefix(configuration.RedisKeyPrefix)
// init redis client
if configuration.RedisUseClusters && configuration.RedisUseSentinel {
log.Panic("REDIS_USE_CLUSTERS and REDIS_USE_SENTINEL cannot both be true")
}
if configuration.RedisUseClusters {
addrs := splitAndTrimCSV(configuration.RedisClusters)
if configuration.RedisDB != 0 {
log.Panic("REDIS_DB must be 0 when REDIS_USE_CLUSTERS is true (Redis Cluster does not support SELECT DB)")
}
addrs := parser.SplitAndTrimCSV(configuration.RedisClusters)
if len(addrs) == 0 {
log.Panic("REDIS_USE_CLUSTERS is true but REDIS_CLUSTERS is empty")
}
@@ -146,7 +152,7 @@ func (p *PluginManager) Launch(configuration *app.Config) {
}
} else if configuration.RedisUseSentinel {
// use Redis Sentinel
sentinels := strings.Split(configuration.RedisSentinels, ",")
sentinels := parser.SplitAndTrimCSV(configuration.RedisSentinels)
if err := cache.InitRedisSentinelClient(
sentinels,
configuration.RedisSentinelServiceName,
@@ -267,17 +273,3 @@ func (p *PluginManager) ExtractPluginAsset(
p.pluginAssetCache.Add(key, assets[path])
return assets[path], nil
}
func splitAndTrimCSV(s string) []string {
if s == "" {
return nil
}
parts := strings.Split(s, ",")
out := make([]string, 0, len(parts))
for _, p := range parts {
if trimmed := strings.TrimSpace(p); trimmed != "" {
out = append(out, trimmed)
}
}
return out
}
+5 -5
View File
@@ -616,14 +616,14 @@ func Expire(key string, time time.Duration, context ...redis.Cmdable) (bool, err
return getCmdable(context...).Expire(ctx, serialKey(key), time).Result()
}
func Transaction(fn func(redis.Pipeliner) error, keys ...string) error {
func Transaction(fn func(redis.Pipeliner) error, watchKeys ...string) error {
if client == nil {
return ErrDBNotInit
}
watchKeys := make([]string, len(keys))
for i, k := range keys {
watchKeys[i] = serialKey(k)
serialized := make([]string, len(watchKeys))
for i, k := range watchKeys {
serialized[i] = serialKey(k)
}
return client.Watch(ctx, func(tx *redis.Tx) error {
@@ -634,7 +634,7 @@ func Transaction(fn func(redis.Pipeliner) error, keys ...string) error {
return nil
}
return err
}, watchKeys...)
}, serialized...)
}
func Publish(channel string, message any, context ...redis.Cmdable) error {
+17
View File
@@ -0,0 +1,17 @@
package parser
import "strings"
func SplitAndTrimCSV(s string) []string {
if s == "" {
return nil
}
parts := strings.Split(s, ",")
out := make([]string, 0, len(parts))
for _, p := range parts {
if trimmed := strings.TrimSpace(p); trimmed != "" {
out = append(out, trimmed)
}
}
return out
}
+37
View File
@@ -0,0 +1,37 @@
package parser
import (
"reflect"
"testing"
)
func TestSplitAndTrimCSV(t *testing.T) {
tests := []struct {
name string
input string
want []string
}{
{"empty string", "", nil},
{"only separators", ",,,", []string{}},
{"only whitespace between separators", " , , ,", []string{}},
{"single value", "a", []string{"a"}},
{"trims surrounding whitespace", " a , b ", []string{"a", "b"}},
{"drops empty segments", "a, ,b", []string{"a", "b"}},
{"preserves inner colons", "host1:6379, host2:6379", []string{"host1:6379", "host2:6379"}},
{"trailing comma", "a,b,", []string{"a", "b"}},
{"leading comma", ",a,b", []string{"a", "b"}},
{"tabs and mixed whitespace", "\ta\t,\nb\n", []string{"a", "b"}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := SplitAndTrimCSV(tt.input)
if len(got) == 0 && len(tt.want) == 0 {
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("SplitAndTrimCSV(%q) = %#v, want %#v", tt.input, got, tt.want)
}
})
}
}