A production-ready, pluggable caching system SDK for Go applications with interface-first design and zero dependencies on concrete implementations.
- Interface-First Design: All caching logic depends on abstractions, not concrete implementations
- Pluggable Backends: Built-in Redis and in-memory implementations, plus support for custom cache engines
- Type Safety: Strict typing throughout - no
interface{}
usage - High-Level Client: JSON marshaling, string operations, GetOrSet patterns
- Statistics: Built-in cache performance metrics
- Production Ready: Modular, testable, and suitable for real production environments
- Zero Circular Dependencies: Clean separation of layers and concerns
package main
import (
"context"
"log"
"time"
"github.com/arash-mosavi/go-caching-system/pkg/gocache"
"github.com/arash-mosavi/go-caching-system/config"
)
func main() {
ctx := context.Background()
// Create Redis cache with custom config
redisConfig := config.DefaultRedisConfig()
redisConfig.Address = "localhost:6379"
redisConfig.Password = "your-password"
cache, err := gocache.NewRedisCache(redisConfig)
if err != nil {
log.Fatal(err)
}
defer cache.Close()
// String operations
err = cache.SetString(ctx, "user:123", "John Doe", 5*time.Minute)
if err != nil {
log.Fatal(err)
}
name, err := cache.GetString(ctx, "user:123")
if err != nil {
log.Fatal(err)
}
log.Printf("User: %s", name)
}
package main
import (
"context"
"log"
"time"
"github.com/arash-mosavi/go-caching-system/pkg/gocache"
)
func main() {
ctx := context.Background()
// Create in-memory cache
cache := gocache.NewMemoryCache()
defer cache.Close()
// JSON operations
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
user := User{ID: 123, Name: "John Doe", Age: 30}
err := cache.SetJSON(ctx, "user:123", user, 10*time.Minute)
if err != nil {
log.Fatal(err)
}
var retrievedUser User
err = cache.GetJSON(ctx, "user:123", &retrievedUser)
if err != nil {
log.Fatal(err)
}
log.Printf("User: %+v", retrievedUser)
}
package main
import (
"context"
"log"
"time"
"github.com/arash-mosavi/go-caching-system/pkg/gocache"
"github.com/arash-mosavi/go-caching-system/cache"
)
// Custom cache that implements cache.Cache interface
type MyCustomCache struct {
// Your implementation here
data map[string][]byte
}
func (c *MyCustomCache) Get(ctx context.Context, key string) ([]byte, error) {
// Your implementation
if value, exists := c.data[key]; exists {
return value, nil
}
return nil, cache.ErrKeyNotFound
}
func (c *MyCustomCache) Set(ctx context.Context, key string, value []byte, ttl time.Duration) error {
// Your implementation
if c.data == nil {
c.data = make(map[string][]byte)
}
c.data[key] = value
return nil
}
func (c *MyCustomCache) Delete(ctx context.Context, key string) error {
delete(c.data, key)
return nil
}
func (c *MyCustomCache) Exists(ctx context.Context, key string) (bool, error) {
_, exists := c.data[key]
return exists, nil
}
func (c *MyCustomCache) Flush(ctx context.Context) error {
c.data = make(map[string][]byte)
return nil
}
func (c *MyCustomCache) Close() error {
return nil
}
func main() {
ctx := context.Background()
// Use your custom cache implementation
customCache := &MyCustomCache{}
cache := gocache.NewCustomCache(customCache)
defer cache.Close()
// Use the same high-level API
err := cache.SetString(ctx, "key", "value", time.Hour)
if err != nil {
log.Fatal(err)
}
}
// Compute expensive operation only if not cached
result, err := cache.GetOrSetString(ctx, "expensive:key", func() (string, error) {
// This function is only called if the key doesn't exist
return computeExpensiveResult(), nil
}, 30*time.Minute)
// Get cache performance metrics (if supported by implementation)
if stats := cache.Stats(); stats != nil {
fmt.Printf("Hit Rate: %.2f%%\n", stats.HitRate())
fmt.Printf("Total Hits: %d\n", stats.TotalHits())
fmt.Printf("Total Misses: %d\n", stats.TotalMisses())
fmt.Printf("Total Operations: %d\n", stats.TotalOperations())
}
The SDK follows a clean, layered architecture:
gocache.go # Package entry point / Public API / Factory functions
pkg/
- gocache/ # Core package implementation
client/ # High-level client with convenience methods
cache/ # Core interfaces and error types
adapters/ # Cache implementation adapters
- redis/ # Redis backend implementation
- memory/ # In-memory backend implementation
config/ # Configuration types and validation
examples/ # Usage examples
- basic/ # Basic usage examples
- tagging/ # Tagging feature examples
- versioning/ # Versioning feature examples
- versioned_tagging/# Combined versioning and tagging examples
cmd/ # Command-line applications
- main.go # Simple demo application
tests/ # Interface compliance and integration tests
run.sh # Linux/macOS run script for examples and tests
run.bat # Windows run script for examples and tests
All cache implementations must satisfy the cache.Cache
interface:
type Cache interface {
Get(ctx context.Context, key string) ([]byte, error)
Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
Delete(ctx context.Context, key string) error
Exists(ctx context.Context, key string) (bool, error)
Flush(ctx context.Context) error
Close() error
}
Optional statistics interface:
type StatsCache interface {
Cache
HitRate() float64
TotalHits() int64
TotalMisses() int64
TotalOperations() int64
}
The SDK provides structured error handling with cache.CacheError
:
if err != nil {
var cacheErr *cache.CacheError
if errors.As(err, &cacheErr) {
log.Printf("Cache operation '%s' failed for key '%s': %v",
cacheErr.Op, cacheErr.Key, cacheErr.Err)
}
}
For Linux/macOS:
# Run the basic example
./run.sh basic
# Run all tests
./run.sh test
# Run the main application
./run.sh main
# Build and run everything
./run.sh all
For Windows:
# Run the basic example
run.bat basic
# Run all tests
run.bat test
# Run the main application
run.bat main
# Build and run everything
run.bat all
Run all tests:
go test ./...
Run specific test packages:
go test ./tests/
go test ./adapters/redis/
go test ./adapters/memory/
This project includes several documentation files:
- README.md: Overview, quick start, and architecture
- USAGE.md: Detailed usage guide and best practices
- README-EXAMPLES.md: Examples and common use cases
- CONTRIBUTING.md: Guidelines for contributing to the project
- Go 1.21+
- Redis server (for Redis backend)
MIT