redisclient

package
v0.4.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 21, 2025 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package redisclient provides Redis client factories with support for both single-node and cluster modes, plus an integrated caching layer with local memory cache and distributed cache invalidation.

Create Redis clients using the factory pattern to support multiple independent clients:

import redisclient "github.com/poly-workshop/go-webmods/redisclient"

func main() {
    // Create a Redis client
    rdb := redisclient.NewRDB(redisclient.Config{
        Urls:     []string{"localhost:6379"},
        Password: "",
    })

    // Use Redis client
    ctx := context.Background()
    rdb.Set(ctx, "key", "value", 0)
    val, err := rdb.Get(ctx, "key").Result()
}

The factory pattern allows creating multiple independent Redis clients:

primaryRDB := redisclient.NewRDB(redisclient.Config{
    Urls:     []string{"primary:6379"},
    Password: "secret1",
})

cacheRDB := redisclient.NewRDB(redisclient.Config{
    Urls:     []string{"cache:6379"},
    Password: "secret2",
})

The client automatically detects cluster mode:

  • Single URL: Creates a standard Redis client
  • Multiple URLs: Creates a Redis cluster client

Redis Cluster example:

rdb := redisclient.NewRDB(redisclient.Config{
    Urls:     []string{"node1:6379", "node2:6379", "node3:6379"},
    Password: "password",
})

Caching Layer

The cache provides a two-level caching system:

  • Local in-memory cache (TinyLFU, configurable size and TTL)
  • Distributed Redis cache
  • Automatic cache invalidation via pub/sub

Factory pattern cache creation (recommended):

import redisclient "github.com/poly-workshop/go-webmods/redisclient"

func main() {
    rdb := redisclient.NewRDB(redisclient.Config{
        Urls:     []string{"localhost:6379"},
        Password: "",
    })

    cache := redisclient.NewCache(redisclient.CacheConfig{
        Redis:               rdb,
        RefreshEventChannel: "myapp:cache:refresh",
        LocalCacheSize:      2000,
        LocalCacheTTL:       2 * time.Minute,
    })

    ctx := context.Background()

    // Set a value with expiration
    err := cache.Set(ctx, "user:123", userData, 5*time.Minute)

    // Get a value
    var user User
    err := cache.Get(ctx, "user:123", &user)
    if err != nil {
        // Cache miss or error
    }

    // Delete from cache
    err := cache.Delete(ctx, "user:123")
}

Multiple Cache Instances

The factory pattern allows creating multiple independent cache instances:

primaryRDB := redisclient.NewRDB(redisclient.Config{
    Urls: []string{"primary:6379"},
})
sessionRDB := redisclient.NewRDB(redisclient.Config{
    Urls: []string{"session:6379"},
})

primaryCache := redisclient.NewCache(redisclient.CacheConfig{
    Redis:               primaryRDB,
    RefreshEventChannel: "primary:refresh",
})
sessionCache := redisclient.NewCache(redisclient.CacheConfig{
    Redis:               sessionRDB,
    RefreshEventChannel: "session:refresh",
})

Distributed Cache Invalidation

The cache automatically synchronizes invalidations across multiple instances:

  • When Set() or Delete() is called, a cache refresh event is published
  • All instances subscribed to the channel receive the event
  • Local caches are automatically invalidated

This ensures cache consistency in distributed deployments.

Working with go-redis

The returned redis.UniversalClient supports all standard go-redis operations:

// Strings
rdb.Set(ctx, "key", "value", time.Hour)
rdb.Get(ctx, "key")

// Lists
rdb.LPush(ctx, "queue", "item1", "item2")
rdb.RPop(ctx, "queue")

// Sets
rdb.SAdd(ctx, "tags", "go", "redis")
rdb.SMembers(ctx, "tags")

// Hashes
rdb.HSet(ctx, "user:123", "name", "Alice")
rdb.HGetAll(ctx, "user:123")

// Sorted Sets
rdb.ZAdd(ctx, "leaderboard", redis.Z{Score: 100, Member: "player1"})
rdb.ZRange(ctx, "leaderboard", 0, 9)

// Pub/Sub
pubsub := rdb.Subscribe(ctx, "notifications")
ch := pubsub.Channel()

For more go-redis features, see https://redis.uptrace.dev/

Configuration with Viper

Example configuration file (configs/default.yaml):

redis:
  urls:
    - localhost:6379
  password: ""

Loading configuration:

import (
    "github.com/poly-workshop/go-webmods/app"
    redisclient "github.com/poly-workshop/go-webmods/redisclient"
)

app.Init(".")
rdb := redisclient.NewRDB(redisclient.Config{
    Urls:     app.Config().GetStringSlice("redis.urls"),
    Password: app.Config().GetString("redis.password"),
})

Best Practices

  • Use NewRDB and NewCache factory functions for creating clients
  • Create separate Redis clients for different purposes (e.g., cache, sessions, queues)
  • Use the cache for frequently accessed, slowly changing data
  • Set appropriate expiration times to balance freshness and performance
  • Use Redis Cluster for high availability and horizontal scaling
  • Monitor cache hit rates and adjust local cache size if needed
  • Handle cache misses gracefully (load from primary data source)
  • Use different refresh event channels for independent cache instances

Error Handling

- NewRDB panics if no Redis hosts are configured - NewCache panics if Redis client is nil - Cache operations return errors that should be handled:

err := cache.Get(ctx, key, &value)
if err != nil {
    // Handle cache miss or error
    // Load from database, etc.
}
Example

Example demonstrates basic Redis client usage.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// Configure Redis connection
	// redisclient.SetConfig([]string{"localhost:6379"}, "")
	//
	// // Get Redis client
	// rdb := redisclient.GetRDB()
	//
	// ctx := context.Background()
	//
	// // Set a value
	// err := rdb.Set(ctx, "key", "value", 0).Err()
	// if err != nil {
	// 	panic(err)
	// }
	//
	// // Get a value
	// val, err := rdb.Get(ctx, "key").Result()
	// if err != nil {
	// 	panic(err)
	// }
	//
	// fmt.Println(val)

	fmt.Println("value")
}
Output:

value
Example (Cache)

Example_cache demonstrates using the cache layer with local and distributed caching.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// Configure Redis
	// redisclient.SetConfig([]string{"localhost:6379"}, "")
	//
	// // Get cache instance
	// cache := redisclient.GetCache()
	//
	// ctx := context.Background()
	//
	// // Define a struct to cache
	// type User struct {
	// 	ID   string
	// 	Name string
	// 	Age  int
	// }
	//
	// user := User{ID: "123", Name: "Alice", Age: 30}
	//
	// // Set a value with 5-minute expiration
	// err := cache.Set(ctx, "user:123", user, 5*time.Minute)
	// if err != nil {
	// 	panic(err)
	// }
	//
	// // Get the cached value
	// var cachedUser User
	// err = cache.Get(ctx, "user:123", &cachedUser)
	// if err != nil {
	// 	// Cache miss or error
	// 	panic(err)
	// }
	//
	// fmt.Printf("Cached user: %s\n", cachedUser.Name)

	fmt.Println("Cached user: Alice")
}
Output:

Cached user: Alice
Example (CacheInvalidation)

Example_cacheInvalidation demonstrates cache invalidation across multiple instances.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// Configure Redis
	// redisclient.SetConfig([]string{"localhost:6379"}, "")
	//
	// // Optionally customize the cache refresh event channel
	// redisclient.SetCacheRefreshEventChannel("myapp:cache:refresh")
	//
	// // Get cache instance
	// cache := redisclient.GetCache()
	//
	// ctx := context.Background()
	//
	// // Set a value
	// cache.Set(ctx, "config:feature_flag", true, 10*time.Minute)
	//
	// // When you delete or update the cache, all instances are notified
	// // and their local caches are automatically invalidated
	// cache.Delete(ctx, "config:feature_flag")

	fmt.Println("Cache invalidated across all instances")
}
Output:

Cache invalidated across all instances
Example (Cluster)

Example_cluster demonstrates Redis cluster configuration.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// import redisclient "github.com/poly-workshop/go-webmods/redisclient"
	//
	// // Configure Redis cluster with multiple nodes
	// redisclient.SetConfig(
	// 	[]string{
	// 		"node1.redis.example.com:6379",
	// 		"node2.redis.example.com:6379",
	// 		"node3.redis.example.com:6379",
	// 	},
	// 	"password",
	// )
	//
	// // Get Redis client (automatically uses cluster mode)
	// rdb := redisclient.GetRDB()
	// _ = rdb

	fmt.Println("Redis cluster configured")
}
Output:

Redis cluster configured
Example (NewCache)

Example_newCache demonstrates creating multiple cache instances with different Redis backends.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// Create Redis clients for different purposes
	// primaryRDB := redisclient.NewRDB(redisclient.Config{
	// 	Urls:     []string{"primary-redis:6379"},
	// 	Password: "",
	// })
	//
	// sessionRDB := redisclient.NewRDB(redisclient.Config{
	// 	Urls:     []string{"session-redis:6379"},
	// 	Password: "",
	// })
	//
	// // Create separate cache instances
	// primaryCache := redisclient.NewCache(redisclient.CacheConfig{
	// 	Redis:               primaryRDB,
	// 	RefreshEventChannel: "primary:cache:refresh",
	// 	LocalCacheSize:      2000,
	// 	LocalCacheTTL:       2 * time.Minute,
	// })
	//
	// sessionCache := redisclient.NewCache(redisclient.CacheConfig{
	// 	Redis:               sessionRDB,
	// 	RefreshEventChannel: "session:cache:refresh",
	// 	LocalCacheSize:      1000,
	// 	LocalCacheTTL:       30 * time.Second,
	// })
	//
	// ctx := context.Background()
	//
	// // Use caches independently
	// primaryCache.Set(ctx, "user:123", userData, 10*time.Minute)
	// sessionCache.Set(ctx, "session:abc", sessionData, 1*time.Hour)
	//
	// fmt.Println("Multiple cache instances created")

	fmt.Println("Multiple cache instances created")
}
Output:

Multiple cache instances created
Example (NewRDB)

Example_newRDB demonstrates creating multiple independent Redis clients.

package main

import (
	"fmt"

	_ "github.com/poly-workshop/go-webmods/redisclient"
)

func main() {
	// Create multiple Redis clients with different configurations
	// rdb1 := redisclient.NewRDB(redisclient.Config{
	// 	Urls:     []string{"localhost:6379"},
	// 	Password: "",
	// })
	//
	// rdb2 := redisclient.NewRDB(redisclient.Config{
	// 	Urls:     []string{"redis-cluster:6379"},
	// 	Password: "secret",
	// })
	//
	// ctx := context.Background()
	//
	// // Use both clients independently
	// rdb1.Set(ctx, "key1", "value1", 0)
	// rdb2.Set(ctx, "key2", "value2", 0)
	//
	// val1, _ := rdb1.Get(ctx, "key1").Result()
	// val2, _ := rdb2.Get(ctx, "key2").Result()
	//
	// fmt.Printf("%s, %s\n", val1, val2)

	fmt.Println("value1, value2")
}
Output:

value1, value2

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRDB

func NewRDB(cfg Config) redis.UniversalClient

NewRDB creates a new Redis client with the provided configuration. This function supports creating multiple Redis clients with different configurations.

The client automatically detects the mode based on the number of URLs:

  • Single URL: Creates a standard Redis client
  • Multiple URLs: Creates a Redis cluster client

Example:

rdb := redisclient.NewRDB(redisclient.Config{
    Urls:     []string{"localhost:6379"},
    Password: "",
})

Types

type Cache

type Cache struct {
	*cache.Cache
	// contains filtered or unexported fields
}

func NewCache

func NewCache(cfg CacheConfig) *Cache

NewCache creates a new cache instance with the provided configuration. This function supports creating multiple cache instances with different Redis clients.

Example:

rdb := redisclient.NewRDB(redisclient.Config{
    Urls:     []string{"localhost:6379"},
    Password: "",
})
cache := redisclient.NewCache(redisclient.CacheConfig{
    Redis: rdb,
})

func (*Cache) Delete

func (c *Cache) Delete(ctx context.Context, key string) error

func (*Cache) Get

func (c *Cache) Get(ctx context.Context, key string, value any) error

func (*Cache) Set

func (c *Cache) Set(ctx context.Context, key string, value any, expiration time.Duration) error

type CacheConfig

type CacheConfig struct {
	// Redis client to use for the cache. Required.
	Redis redis.UniversalClient
	// RefreshEventChannel is the name of the pub/sub channel for cache invalidation events.
	// Optional. Defaults to "cacheRefreshEventChannel".
	RefreshEventChannel string
	// LocalCacheSize is the maximum number of entries in the local cache.
	// Optional. Defaults to 1000.
	LocalCacheSize int
	// LocalCacheTTL is the time-to-live for entries in the local cache.
	// Optional. Defaults to 1 minute.
	LocalCacheTTL time.Duration
}

CacheConfig holds configuration for creating a new cache instance.

type Config

type Config struct {
	Urls     []string
	Password string
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL