Files
goclaw/cmd/gateway_redis.go
T
viettranx 0d3230b2bf feat(cache): add build-tag-gated Redis cache backend
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)
2026-03-07 19:27:24 +07:00

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()
}
}