cacher

package
v1.30.0 Latest Latest
Warning

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

Go to latest
Published: Dec 8, 2024 License: MIT Imports: 7 Imported by: 0

README

Cache Library

Efficient and Type-safe Redis-based Caching for Go Applications

Go Report Card GoDoc

  • Connection pooling for optimal performance
  • Automatic key prefixing to prevent collisions
  • Distributed tracing integration
  • Configurable cache TTLs
  • Bulk operations support
  • JSON serialization helpers
  • Comprehensive error handling

Installation

package main

import (
    "context"
    "log"
    
    "github.com/SolomonAIEngineering/backend-core-library/cacher"
    "github.com/gomodule/redigo/redis"
    "go.uber.org/zap"
)

func main() {
    // Initialize Redis pool with recommended settings
    pool := &redis.Pool{
        MaxIdle:     80,
        MaxActive:   12000,
        IdleTimeout: 240 * time.Second,
        Wait:        true,
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", "localhost:6379")
        },
    }

    // Create cache client with all required options
    client, err := cacher.New(
        cacher.WithRedisConn(pool),
        cacher.WithLogger(zap.L()),
        cacher.WithServiceName("my-service"),
        cacher.WithCacheTTLInSeconds(3600),
    )
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()
    
    // Basic write operation
    if err := client.WriteToCache(ctx, "user:123", []byte("data")); err != nil {
        log.Printf("Failed to write to cache: %v", err)
    }
}

Advanced Usage

Type-Safe Cache Keys

The library provides a type-safe way to manage cache keys:

// Define type-safe cache keys
key := cacher.NewCacheKey("user")
userKey := key.Enrich("123") // Results in "user:123"

Batch Operations with Pipeline

Efficiently handle multiple cache operations:

// Write multiple values atomically
data := map[string][]byte{
    "key1": []byte("value1"),
    "key2": []byte("value2"),
}
err := client.WriteManyToCache(ctx, data)

// Read multiple values
values, err := client.GetManyFromCache(ctx, []string{"key1", "key2"})

Custom TTL Support

Set custom TTL for specific cache entries:

err := client.WriteToCacheWithTTL(ctx, "temp-key", []byte("data"), 300) // 5 minutes TTL

Configuration Options

Option Description Required Default
WithRedisConn Redis connection pool Yes -
WithLogger Zap logger instance Yes -
WithServiceName Service name for key prefixing Yes -
WithCacheTTLInSeconds Default TTL for cache entries Yes -
WithIntrumentationClient Instrumentation client No nil

Best Practices

Connection Pool Management

pool := &redis.Pool{
    MaxIdle:     80,
    MaxActive:   12000,
    IdleTimeout: 240 * time.Second,
    Wait:        true,
    TestOnBorrow: func(c redis.Conn, t time.Time) error {
        _, err := c.Do("PING")
        return err
    },
}
defer pool.Close()

Error Handling

// Always check for errors and implement retries for critical operations
value, err := client.GetFromCache(ctx, key)
if err != nil {
    if errors.Is(err, redis.ErrNil) {
        // Handle cache miss
    } else {
        // Handle other errors
    }
}

Key Management

// Use service name for automatic key prefixing
client, _ := cacher.New(
    cacher.WithServiceName("user-service"),
    // ... other options
)

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support


Built with ❤️ by Solomon AI Engineering

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CacheKey

type CacheKey string

func NewCacheKey

func NewCacheKey(key string) CacheKey

NewCacheKey creates a new CacheKey with the given key.

func (CacheKey) Enrich

func (c CacheKey) Enrich(value string) string

Enrich enriches the cache key with the given value.

func (CacheKey) String

func (c CacheKey) String() string

String returns the string representation of the cache key.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client implements a Redis cache client with connection pooling and instrumentation support. It automatically handles connection management, key prefixing, and tracing of Redis operations.

func New

func New(opts ...Option) (*Client, error)

New creates a new Redis cache client with the provided options. Example usage:

client, err := cacher.New(
    cacher.WithLogger(logger),
    cacher.WithRedisConn(pool),
    cacher.WithServiceName("myservice"),
    cacher.WithCacheTTLInSeconds(3600),
)

func (*Client) DeleteFromCache

func (s *Client) DeleteFromCache(ctx context.Context, key string) error

DeleteFromCache removes a value from the cache. It's safe to delete non-existent keys. Example usage:

err := client.DeleteFromCache(ctx, "user:123")

func (*Client) GetFromCache

func (s *Client) GetFromCache(ctx context.Context, key string) ([]byte, error)

GetFromCache retrieves a value from the cache by key. Returns nil and an error if the key doesn't exist. Example usage:

data, err := client.GetFromCache(ctx, "user:123")
if err != nil {
    if err == redis.ErrNil {
        // Handle cache miss
    }
    return err
}

func (*Client) GetManyFromCache

func (s *Client) GetManyFromCache(ctx context.Context, keys []string) ([][]byte, error)

GetManyFromCache retrieves multiple values from the cache in a single operation. If any key is missing, it returns an error. For partial success/failure handling, use individual GetFromCache calls. Example usage:

keys := []string{"user:123", "user:456"}
values, err := client.GetManyFromCache(ctx, keys)

func (*Client) Validate

func (c *Client) Validate() error

Validate checks that all required fields are properly configured. It returns an error if any required configuration is missing or invalid.

Required configurations: - Redis connection pool - Logger - Service name - Cache TTL > 0

The instrumentation client is optional - a warning is logged if not provided.

func (*Client) WriteAnyToCache

func (s *Client) WriteAnyToCache(ctx context.Context, key string, value interface{}) error

WriteAnyToCache marshals any JSON-serializable value and writes it to the cache. This is a convenience wrapper around WriteToCache with JSON marshaling. Example usage:

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}
user := User{Name: "John", Age: 30}
err := client.WriteAnyToCache(ctx, "user:123", user)

func (*Client) WriteManyToCache

func (s *Client) WriteManyToCache(ctx context.Context, pairs map[string][]byte) error

WriteManyToCache writes multiple key-value pairs to the cache atomically. This is more efficient than multiple individual writes for bulk operations. Example usage:

pairs := map[string][]byte{
    "user:123": []byte(`{"name":"John"}`),
    "user:456": []byte(`{"name":"Jane"}`),
}
err := client.WriteManyToCache(ctx, pairs)

func (*Client) WriteToCache

func (s *Client) WriteToCache(ctx context.Context, key string, value []byte) error

WriteToCache writes a value to the cache with the configured TTL. The key will be automatically prefixed with the service name. Example usage:

err := client.WriteToCache(ctx, "user:123", []byte(`{"name":"John"}`))

func (*Client) WriteToCacheWithTTL added in v1.20.0

func (s *Client) WriteToCacheWithTTL(ctx context.Context, key string, value []byte, timeToLiveInSeconds int) error

WriteToCacheWithTTL writes a value to the cache with a custom TTL. If timeToLiveInSeconds is <= 0, defaults to 60 seconds. Example usage:

// Cache for 5 minutes
err := client.WriteToCacheWithTTL(ctx, "temp:123", data, 300)

type Option

type Option func(*Client)

Option defines a function type that configures a Client. Options are used with New() to configure the client instance.

func WithCacheTTLInSeconds

func WithCacheTTLInSeconds(ttl int) Option

WithCacheTTLInSeconds sets the default time-to-live for cache entries in seconds. This TTL is used for all cache writes unless overridden by WriteToCacheWithTTL.

Example:

// Set default TTL to 1 hour
client, err := cacher.New(
    cacher.WithCacheTTLInSeconds(3600),
)

func WithIntrumentationClient

func WithIntrumentationClient(client *instrumentation.Client) Option

WithIntrumentationClient enables distributed tracing for cache operations. When configured, each cache operation will create a trace span for monitoring.

Example:

instrClient := instrumentation.NewClient()
client, err := cacher.New(
    cacher.WithIntrumentationClient(instrClient),
)

func WithLogger

func WithLogger(logger *zap.Logger) Option

WithLogger configures the logging instance for the cache client. The logger is used to record operational events and errors.

Example:

logger := zap.NewProduction()
client, err := cacher.New(
    cacher.WithLogger(logger),
)

func WithRedisConn

func WithRedisConn(connPool *redis.Pool) Option

WithRedisConn configures the Redis connection pool. The pool manages a set of Redis connections for optimal performance.

Example:

pool := &redis.Pool{
    MaxIdle:     3,
    IdleTimeout: 240 * time.Second,
    Dial: func() (redis.Conn, error) {
        return redis.Dial("tcp", "localhost:6379")
    },
}
client, err := cacher.New(
    cacher.WithRedisConn(pool),
)

func WithServiceName

func WithServiceName(name string) Option

WithServiceName sets the service name used for key prefixing. The service name is prepended to all cache keys to prevent collisions when multiple services share the same Redis instance.

Example:

client, err := cacher.New(
    cacher.WithServiceName("user-service"),
)

Jump to

Keyboard shortcuts

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