How to Configure Redis Cache Backend in Gorig Using the Cache Module
To configure Redis in Gorig, set the redis.addr, redis.password, and redis.db configuration keys, then instantiate a cache using cache.New[T](cache.Redis) which returns a generic RedisCache[T] wrapper backed by go-redis/v8.
Gorig provides a generic, multi-backend cache subsystem that supports in-memory, file-based, SQLite, and Redis storage. When you configure Redis cache backend in Gorig using the cache module, the framework creates a singleton redis.Client from the go-redis/v8 library and wraps it in a type-safe RedisCache[T] that implements the Cache[T] interface.
Configuration Prerequisites
Gorig reads Redis connection parameters via the configuration helper in utils/cofigure/cfg.go. The factory function initRedisCache in cache/cache.redis.go expects three specific keys to build the redis.Options struct.
Required Configuration Keys
| Config Key | Purpose | Default Behavior |
|---|---|---|
redis.addr |
Redis server address in host:port format |
If empty or omitted, Redis is disabled and initialization is skipped |
redis.password |
Password for Redis AUTH command | Empty string (no authentication) |
redis.db |
Logical database number as a string | "0" (converted to integer 0) |
Setting Configuration Values
You can provide these values via environment variables or JSON/YAML configuration files. The configure package automatically maps environment variables to these keys.
Using environment variables:
export REDIS_ADDR="127.0.0.1:6379"
export REDIS_PASSWORD="mySecret"
export REDIS_DB="0"
Using a YAML configuration file:
redis:
addr: "127.0.0.1:6379"
password: "mySecret"
db: "0"
Instantiating the Redis Cache
Once the configuration is loaded—typically during bootstrap/startup.go execution—you create a Redis-backed cache through the public API in cache/cache.go.
The Factory Function
The generic constructor cache.New[T any] selects the backend based on the cache.Type argument. Passing cache.Redis triggers the Redis initialization path:
import "github.com/jom-io/gorig/cache"
// Create a Redis-backed cache for a custom type
userCache := cache.New[UserProfile](cache.Redis)
Internally, this calls GetRedisInstance[T] (defined in cache/cache.redis.go), which lazily builds the *redis.Client if it does not already exist and wraps it in a *RedisCache[T].
The RedisCache Wrapper
RedisCache[T] implements the Cache[T] interface, providing methods like Set, Get, LPop, and RPush. All values are automatically serialized to JSON before storage and deserialized on retrieval, allowing you to cache any struct that can be marshaled.
Architecture and Implementation Details
Understanding the internal flow helps debug connection issues and optimize usage.
Lazy Singleton Initialization
- First Call: When
cache.New[T](cache.Redis)is invoked,GetRedisInstancechecks the package-levelredisInstancevariable. - Client Construction: If
nil, it callsinitRedisCache, which reads the threeredis.*config keys viaconfigure.GetStringand creates aredis.Client. - Reuse: The client is stored in
redisInstancefor the process lifetime, ensuring all cache instances share a single connection pool. - Disabled State: If
redis.addris empty, the initialization skips client creation, allowing the application to start without Redis.
Serialization Strategy
All operations in RedisCache[T] (see Set, Get, RPush in cache/cache.redis.go) use JSON marshaling. This design choice enables the message broker in mid/messagex/broker.simple.go to store complex message structs in Redis lists transparently.
Practical Code Examples
Basic Redis Setup with Environment Variables
Ensure your application loads configuration before creating caches:
package main
import (
"fmt"
"time"
"github.com/jom-io/gorig/cache"
)
type Product struct {
SKU string `json:"sku"`
Price float64 `json:"price"`
}
func main() {
// Configuration is loaded automatically from env vars or config files
// Create a Redis cache for Product structs
productCache := cache.New[Product](cache.Redis)
// Store with 5-minute TTL
productCache.Set("sku:123", Product{SKU: "123", Price: 99.99}, 5*time.Minute)
// Retrieve
prod, err := productCache.Get("sku:123")
if err != nil {
fmt.Println("Cache miss or error:", err)
return
}
fmt.Printf("Cached product: %+v\n", prod)
}
Multi-Level Caching Strategy
Combine in-memory speed with Redis durability using cache.Tool:
func NewProductCacheTool() *cache.Tool[Product] {
// L1: Fast in-memory cache with 1-minute TTL
memCache := cache.New[Product](cache.Memory, time.Minute)
// L2: Shared Redis cache
redisCache := cache.New[Product](cache.Redis)
// Loader fetches from database on cache miss
loader := func(key string) (Product, error) {
// Database fetch logic here
return Product{SKU: key, Price: 0.0}, nil
}
return cache.NewCacheTool[Product](
context.Background(),
[]cache.Cache[Product]{memCache, redisCache},
loader,
)
}
Using Redis as a Message Queue
The messagex package uses the Redis cache internally for distributed messaging:
import "github.com/jom-io/gorig/mid/messagex"
// Creates a broker that uses Redis lists (RPush/BRPop) for queuing
broker := messagex.NewSimpleByType(messagex.Redis)
This leverages RedisCache[Message] to serialize messages as JSON before pushing them to Redis queues.
Summary
- Set
redis.addrto enable Redis; if omitted, the cache module skips Redis initialization entirely. - Use
cache.New[T](cache.Redis)to obtain a type-safeRedisCache[T]instance that implements the genericCache[T]interface. - Configuration is read from environment variables or config files via
utils/cofigure/cfg.go, supportingredis.addr,redis.password, andredis.db. - JSON serialization is handled automatically by the wrapper, allowing complex Go structs to be stored directly.
- Singleton pattern ensures efficient connection reuse through
GetRedisInstanceincache/cache.redis.go. - Integration with higher-level components like the message broker in
mid/messagex/broker.simple.goworks transparently.
Frequently Asked Questions
What happens if redis.addr is not configured?
If redis.addr is empty or undefined, initRedisCache in cache/cache.redis.go skips client creation entirely. The application starts successfully but Redis caching is unavailable; components attempting to use it may encounter errors or fall back to alternative cache types depending on implementation.
How does Gorig handle Redis authentication?
The redis.password config key is passed directly to the redis.Options struct when constructing the client in cache/cache.redis.go. If left empty, the client connects without authentication. For production environments, set REDIS_PASSWORD or the equivalent config file key.
Can I use multiple Redis databases in the same application?
The current implementation in cache/cache.redis.go maintains a single global redisInstance configured with one redis.db value. To use multiple databases simultaneously, you would need to instantiate separate redis.Client instances manually, as the singleton pattern assumes a single shared connection pool.
Does RedisCache support complex Go types?
Yes. RedisCache[T] uses JSON marshaling for all values via the standard encoding/json package. As long as your type T is JSON-serializable (structs with exported fields, basic types, slices, maps), it can be cached. The wrapper handles serialization in methods like Set and deserialization in Get automatically.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →