mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 06:10:46 +00:00
0d3230b2bf
Add optional Redis cache support via `go build -tags redis`, following the same paired-stub pattern as OTel and Tailscale. The Cache[V] interface is unchanged; Redis and in-memory implementations are injected at startup without altering usage logic. - Add RedisCache[V] implementation with JSON serialization, fail-open on errors - Add gateway_redis.go / gateway_redis_noop.go paired wiring files - Refactor GroupWriterCache and ContextFileInterceptor to accept injected caches - Add GOCLAW_REDIS_DSN env var, docker-compose.redis.yml overlay - Update Dockerfile and GitHub Actions with ENABLE_REDIS build arg - Add Redis variant to CI matrix (5 variants: latest, otel, tsnet, redis, full)
57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
//go:build redis
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"log/slog"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/cache"
|
|
"github.com/nextlevelbuilder/goclaw/internal/config"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// initRedisClient creates a Redis client when built with -tags redis.
|
|
// Returns nil (typed as any) if GOCLAW_REDIS_DSN is empty or connection fails.
|
|
func initRedisClient(cfg *config.Config) any {
|
|
dsn := cfg.Database.RedisDSN
|
|
if dsn == "" {
|
|
slog.Debug("Redis available but not configured (set GOCLAW_REDIS_DSN)")
|
|
return nil
|
|
}
|
|
client, err := cache.NewRedisClient(dsn)
|
|
if err != nil {
|
|
slog.Warn("Redis connection failed, falling back to in-memory cache", "error", err)
|
|
return nil
|
|
}
|
|
slog.Info("Redis cache connected")
|
|
return client
|
|
}
|
|
|
|
// makeCaches creates typed cache instances backed by Redis (or in-memory if client is nil).
|
|
func makeCaches(raw any) (
|
|
agentCtxCache cache.Cache[[]store.AgentContextFileData],
|
|
userCtxCache cache.Cache[[]store.AgentContextFileData],
|
|
groupWriterCache cache.Cache[[]store.GroupFileWriterData],
|
|
) {
|
|
client, _ := raw.(*redis.Client)
|
|
if client == nil {
|
|
slog.Info("cache backend: in-memory (Redis not connected)")
|
|
return cache.NewInMemoryCache[[]store.AgentContextFileData](),
|
|
cache.NewInMemoryCache[[]store.AgentContextFileData](),
|
|
cache.NewInMemoryCache[[]store.GroupFileWriterData]()
|
|
}
|
|
slog.Info("cache backend: redis")
|
|
return cache.NewRedisCache[[]store.AgentContextFileData](client, "ctx:agent"),
|
|
cache.NewRedisCache[[]store.AgentContextFileData](client, "ctx:user"),
|
|
cache.NewRedisCache[[]store.GroupFileWriterData](client, "grp:writers")
|
|
}
|
|
|
|
// shutdownRedis closes the Redis client connection.
|
|
func shutdownRedis(raw any) {
|
|
if client, ok := raw.(*redis.Client); ok && client != nil {
|
|
client.Close()
|
|
}
|
|
}
|