How to Configure Cache Settings with Redis for Production Deployments in AxonHub

To configure Redis cache settings for production deployments in AxonHub, set the CACHE_TYPE=redis environment variable and provide connection details via REDIS_ADDR, REDIS_PASSWORD, and REDIS_DB, then initialize the typed generic store from internal/pkg/xcache/redis/redis.go.

AxonHub provides a production-ready caching layer through its generic cache abstraction in looplj/axonhub. For high-throughput production environments, the Redis implementation offers typed operations, automatic tag handling, and configurable TTL support that outperforms in-memory alternatives.

Understanding AxonHub's Redis Cache Architecture

The caching system centers on the generic store interface defined in internal/pkg/xcache. The Redis-specific implementation in internal/pkg/xcache/redis/redis.go provides a typed cache store using Go generics, allowing you to cache specific struct types safely.

Key capabilities of the Redis store include:

  • Generic type safety through RedisStore[T] where T is your payload type
  • Automatic tag management for bulk invalidation via Redis sets
  • TTL support on both individual values and tag references
  • Connection pooling via the underlying go-redis client

The configuration loader in conf/conf.go initializes the appropriate store implementation based on environment variables, creating the *redis.Client and passing it to the generic constructor.

Configuring Redis Connection Settings for Production

Production deployments require explicit environment variable configuration to activate Redis and set connection parameters. The configuration loader expects specific variables that map to redis.Options fields.

Set the following environment variables before starting AxonHub:


# Required: Enable Redis backend

export CACHE_TYPE=redis

# Required: Redis server address

export REDIS_ADDR=redis-prod.example.com:6379

# Optional: Authentication

export REDIS_PASSWORD=your-secure-password

# Optional: Database index (default 0)

export REDIS_DB=0

# Production tuning: Connection pool

export REDIS_POOL_SIZE=20

# Production tuning: Timeouts

export REDIS_DIAL_TIMEOUT=5s
export REDIS_READ_TIMEOUT=3s
export REDIS_WRITE_TIMEOUT=3s

In conf/conf.go, the buildCacheStore function processes these variables to construct the client:

// conf/conf.go (excerpt)
func buildCacheStore(cfg *Config) (xcache.Store, error) {
    switch cfg.Cache.Type {
    case "redis":
        rdb := redis.NewClient(&redis.Options{
            Addr:         cfg.Cache.Redis.Addr,
            Password:     cfg.Cache.Redis.Password,
            DB:           cfg.Cache.Redis.DB,
            PoolSize:     cfg.Cache.Redis.PoolSize,
            DialTimeout:  cfg.Cache.Redis.DialTimeout,
        })
        return redis.NewRedisStore[MyData](rdb), nil
    }
}

Implementing Typed Redis Cache Stores

After configuration, instantiate typed cache stores for your specific data structures. The generic implementation in internal/pkg/xcache/redis/redis.go requires a concrete type parameter.

Example implementation for caching UserProfile structs:

package cache

import (
    "os"
    "time"

    "github.com/looplj/axonhub/internal/pkg/xcache/redis"
    "github.com/redis/go-redis/v9"
)

type UserProfile struct {
    ID    string `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

func NewUserProfileCache() (*redis.RedisStore[UserProfile], error) {
    rdb := redis.NewClient(&redis.Options{
        Addr:        os.Getenv("REDIS_ADDR"),
        Password:    os.Getenv("REDIS_PASSWORD"),
        DB:          0,
        PoolSize:    10,
        DialTimeout: 5 * time.Second,
    })

    store := redis.NewRedisStore[UserProfile](rdb)
    return store, nil
}

Usage in application handlers:

func GetUserProfile(ctx context.Context, uid string) (*UserProfile, error) {
    cache, _ := NewUserProfileCache()
    
    // Attempt cache retrieval
    if cached, err := cache.Get(ctx, uid); err == nil {
        return cached, nil
    }
    
    // Database fallback
    profile, err := dbFetchUser(uid)
    if err != nil {
        return nil, err
    }
    
    // Cache with 30-minute TTL and invalidation tag
    _ = cache.Set(ctx, uid, profile,
        cache.WithExpiration(30*time.Minute),
        cache.WithTags([]string{"user_profiles"}))
    
    return profile, nil
}

Production Deployment Best Practices

When deploying AxonHub with Redis in production environments, configure additional resilience and security parameters beyond basic connection settings.

Connection Resilience and Timeouts

Set explicit timeouts to prevent goroutine leaks during network partitions:

export REDIS_DIAL_TIMEOUT=5s
export REDIS_READ_TIMEOUT=3s
export REDIS_WRITE_TIMEOUT=3s
export REDIS_POOL_SIZE=20

These map directly to redis.Options fields in conf/conf.go and ensure the connection pool behaves predictably under load.

TLS Encryption

For production deployments requiring encrypted connections, extend the configuration to include TLS certificates:

// Production TLS configuration
import "crypto/tls"

func buildTLSRedisClient(cfg *Config) *redis.Client {
    return redis.NewClient(&redis.Options{
        Addr:      cfg.Cache.Redis.Addr,
        Password:  cfg.Cache.Redis.Password,
        TLSConfig: &tls.Config{
            MinVersion: tls.VersionTLS12,
        },
        PoolSize: cfg.Cache.Redis.PoolSize,
    })
}

Health Monitoring and Graceful Shutdown

Implement health checks using the Redis ping command, and ensure proper client cleanup during shutdown:

// Health check
func (s *Server) HealthCheck(ctx context.Context) error {
    return s.cacheStore.Client().Ping(ctx).Err()
}

// Graceful shutdown
func (s *Server) Shutdown() {
    if s.cacheStore != nil {
        s.cacheStore.Client().Close()
    }
}

High Availability Clustering

For Redis Cluster deployments, modify the connection initialization to use redis.NewClusterClient instead of redis.NewClient. The internal/pkg/xcache/redis/redis.go implementation works with both because it depends on the RedisClientInterface abstraction rather than concrete client types.

Cache Invalidation and Tag Management

AxonHub's Redis implementation supports tag-based invalidation through Redis sets, enabling bulk cache clearing without iterating individual keys.

The tag system stores references under keys following the pattern gocache_tag_<tag>. When you invalidate a tag, the system removes all associated values.

Example of bulk invalidation:

func InvalidateUserProfiles(ctx context.Context) error {
    cache, _ := NewUserProfileCache()
    
    // Retrieve all keys associated with the tag
    tagKey := fmt.Sprintf("gocache_tag_%s", "user_profiles")
    members, err := cache.Client().SMembers(ctx, tagKey).Result()
    if err != nil {
        return err
    }
    
    // Delete individual cache entries
    for _, key := range members {
        _ = cache.Delete(ctx, key)
    }
    
    // Clean up the tag set itself
    return cache.Client().Del(ctx, tagKey).Err()
}

For full cache resets (e.g., during deployments), use the Clear method which executes FLUSHALL:

// Use with caution in production - clears entire Redis instance
func ClearAllCaches(ctx context.Context) error {
    cache, _ := NewUserProfileCache()
    return cache.Clear(ctx)
}

Summary

Configuring Redis cache settings for production deployments in AxonHub requires:

  • Setting the cache type to redis via the CACHE_TYPE environment variable to activate the Redis backend in conf/conf.go
  • Providing connection parameters including REDIS_ADDR, REDIS_PASSWORD, and REDIS_DB to establish the client in internal/pkg/xcache/redis/redis.go
  • Tuning production options such as REDIS_POOL_SIZE, REDIS_DIAL_TIMEOUT, and TLS configuration for connection resilience and security
  • Implementing typed stores using the generic RedisStore[T] to ensure type-safe cache operations with automatic JSON marshaling
  • Managing invalidation through tag-based clearing or FLUSHALL operations for cache consistency during updates

Frequently Asked Questions

How do I switch from in-memory cache to Redis in AxonHub?

Set the environment variable CACHE_TYPE=redis before starting the application. The configuration loader in conf/conf.go detects this value and initializes the Redis client instead of the default in-memory store. You must also provide REDIS_ADDR pointing to your Redis server endpoint.

What Redis version is required for AxonHub production deployments?

AxonHub uses the go-redis/v9 client library, which supports Redis versions 5.0 and above. For production deployments, Redis 6.0 or later is recommended to leverage TLS encryption and improved ACL support for authentication.

How does AxonHub handle Redis connection failures in production?

The internal/pkg/xcache/redis/redis.go implementation returns errors from underlying Redis commands, allowing your application to implement fallback logic. For connection resilience, configure REDIS_DIAL_TIMEOUT, REDIS_READ_TIMEOUT, and REDIS_WRITE_TIMEOUT in your environment variables to prevent indefinite blocking during network partitions.

Can I use Redis Cluster with AxonHub for high availability?

Yes. While the basic configuration uses redis.NewClient for single-node deployments, the RedisStore in internal/pkg/xcache/redis/redis.go depends on the RedisClientInterface abstraction, which is compatible with redis.NewClusterClient. For clustered deployments, modify the initialization in conf/conf.go to use the cluster client with your REDIS_CLUSTER_NODES configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →