🐹 Cache Directives - Go
Cache Directives - Go
🎯 What Are Cache Directives?
Cache directives (#cache
) in TuskLang allow you to define caching strategies, TTL configuration, invalidation rules, and storage backends directly in your configuration files. They transform static config into executable caching logic.
// Cache directives define your entire caching system
type CacheConfig struct {
Strategies map[string]string tsk:"#cache_strategies"
TTL map[string]string tsk:"#cache_ttl"
Invalidation map[string]string tsk:"#cache_invalidation"
Storage map[string]string tsk:"#cache_storage"
}
🚀 Why Cache Directives Matter
Traditional Caching Development
// Old way - scattered across multiple files
func main() {
// Cache configuration scattered
redisClient := redis.NewClient(&redis.Options{
Addr: os.Getenv("REDIS_ADDR"),
DB: 0,
})
// Cache logic defined in code
cache := cache.New(redisClient)
// Manual cache operations
func getUser(id string) (*User, error) {
// Check cache
if cached, err := cache.Get("user:" + id); err == nil {
return cached.(*User), nil
}
// Fetch from database
user, err := db.GetUser(id)
if err != nil {
return nil, err
}
// Store in cache
cache.Set("user:"+id, user, 30*time.Minute)
return user, nil
}
}
TuskLang Cache Directives - Declarative & Dynamic
cache.tsk - Complete cache definition
cache_strategies: #cache("""
user_cache -> User data caching
ttl: 30m
key_pattern: "user:{id}"
storage: "redis"
invalidation: "on_update"
post_cache -> Post data caching
ttl: 1h
key_pattern: "post:{id}"
storage: "redis"
invalidation: "on_update"
compression: true
api_cache -> API response caching
ttl: 5m
key_pattern: "api:{method}:{path}:{params}"
storage: "memory"
invalidation: "time_based"
headers: ["ETag", "Last-Modified"]
session_cache -> Session data caching
ttl: 24h
key_pattern: "session:{id}"
storage: "redis"
invalidation: "on_logout"
security: "encrypted"
""")cache_storage: #cache("""
redis -> Redis cache storage
url: #env("REDIS_URL")
db: 0
pool_size: 10
max_retries: 3
memory -> In-memory cache storage
max_size: 1000
cleanup_interval: 5m
eviction_policy: "lru"
file -> File-based cache storage
path: "/tmp/cache"
max_size: 100MB
compression: true
""")
cache_invalidation: #cache("""
on_update -> Invalidate on data update
events: ["user_updated", "post_updated"]
patterns: ["user:{id}", "post:{id}"]
time_based -> Time-based invalidation
interval: 1h
patterns: ["api:*"]
manual -> Manual invalidation
endpoints: ["/cache/clear", "/cache/invalidate"]
patterns: ["*"]
""")
📋 Cache Directive Types
1. Strategy Directives (#cache_strategies
)
- Cache strategy definitions
- TTL configuration
- Key patterns
- Storage backends2. TTL Directives (#cache_ttl
)
- Time-to-live configuration
- Dynamic TTL based on data
- TTL inheritance
- TTL overrides3. Invalidation Directives (#cache_invalidation
)
- Cache invalidation rules
- Event-based invalidation
- Pattern-based invalidation
- Manual invalidation4. Storage Directives (#cache_storage
)
- Storage backend configuration
- Connection pooling
- Performance settings
- Security features🔧 Basic Cache Directive Syntax
Simple Cache Strategy
Basic cache strategy
user_cache: #cache("user:{id} -> 30m")
Cache Strategy with Configuration
Cache strategy with detailed configuration
post_cache: #cache("""
key_pattern: "post:{id}"
ttl: 1h
storage: "redis"
compression: true
invalidation: "on_update"
""")
Multiple Cache Strategies
Multiple cache strategies
cache_strategies: #cache("""
users -> "user:{id}" -> 30m -> redis
posts -> "post:{id}" -> 1h -> redis
api -> "api:{method}:{path}" -> 5m -> memory
sessions -> "session:{id}" -> 24h -> redis
""")
🎯 Go Integration Patterns
Struct Tags for Cache Directives
type CacheConfig struct {
// Cache strategies
Strategies string tsk:"#cache_strategies"
// TTL configuration
TTL string tsk:"#cache_ttl"
// Invalidation rules
Invalidation string tsk:"#cache_invalidation"
// Storage configuration
Storage string tsk:"#cache_storage"
}
Cache Application Setup
package mainimport (
"github.com/tusklang/go-sdk"
"github.com/gorilla/mux"
"net/http"
)
func main() {
// Load cache configuration
config := tusk.LoadConfig("cache.tsk")
var cacheConfig CacheConfig
config.Unmarshal(&cacheConfig)
// Create cache system from directives
cache := tusk.NewCacheSystem(cacheConfig)
// Create router
router := mux.NewRouter()
// Apply cache middleware
tusk.ApplyCacheMiddleware(router, cache)
// Start server
http.ListenAndServe(":8080", router)
}
Cache Handler Implementation
package cacheimport (
"context"
"encoding/json"
"fmt"
"time"
"github.com/go-redis/redis/v8"
)
// Cache interface
type Cache interface {
Get(ctx context.Context, key string) (interface{}, error)
Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error
Delete(ctx context.Context, key string) error
Clear(ctx context.Context, pattern string) error
}
// Redis cache implementation
type RedisCache struct {
client *redis.Client
}
func NewRedisCache(url string) (*RedisCache, error) {
client := redis.NewClient(&redis.Options{
Addr: url,
DB: 0,
})
// Test connection
ctx := context.Background()
if err := client.Ping(ctx).Err(); err != nil {
return nil, fmt.Errorf("failed to connect to Redis: %v", err)
}
return &RedisCache{client: client}, nil
}
func (rc *RedisCache) Get(ctx context.Context, key string) (interface{}, error) {
data, err := rc.client.Get(ctx, key).Bytes()
if err != nil {
if err == redis.Nil {
return nil, ErrCacheMiss
}
return nil, err
}
// Deserialize data
var value interface{}
if err := json.Unmarshal(data, &value); err != nil {
return nil, fmt.Errorf("failed to deserialize cached data: %v", err)
}
return value, nil
}
func (rc *RedisCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
// Serialize data
data, err := json.Marshal(value)
if err != nil {
return fmt.Errorf("failed to serialize data for caching: %v", err)
}
// Store in Redis
return rc.client.Set(ctx, key, data, ttl).Err()
}
func (rc *RedisCache) Delete(ctx context.Context, key string) error {
return rc.client.Del(ctx, key).Err()
}
func (rc *RedisCache) Clear(ctx context.Context, pattern string) error {
keys, err := rc.client.Keys(ctx, pattern).Result()
if err != nil {
return err
}
if len(keys) > 0 {
return rc.client.Del(ctx, keys...).Err()
}
return nil
}
// Memory cache implementation
type MemoryCache struct {
store map[string]cacheEntry
mu sync.RWMutex
ttl time.Duration
}
type cacheEntry struct {
value interface{}
expiration time.Time
}
func NewMemoryCache(ttl time.Duration) *MemoryCache {
mc := &MemoryCache{
store: make(map[string]cacheEntry),
ttl: ttl,
}
// Start cleanup goroutine
go mc.cleanup()
return mc
}
func (mc *MemoryCache) Get(ctx context.Context, key string) (interface{}, error) {
mc.mu.RLock()
defer mc.mu.RUnlock()
entry, exists := mc.store[key]
if !exists {
return nil, ErrCacheMiss
}
if time.Now().After(entry.expiration) {
delete(mc.store, key)
return nil, ErrCacheMiss
}
return entry.value, nil
}
func (mc *MemoryCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
mc.mu.Lock()
defer mc.mu.Unlock()
expiration := time.Now().Add(ttl)
mc.store[key] = cacheEntry{
value: value,
expiration: expiration,
}
return nil
}
func (mc *MemoryCache) Delete(ctx context.Context, key string) error {
mc.mu.Lock()
defer mc.mu.Unlock()
delete(mc.store, key)
return nil
}
func (mc *MemoryCache) Clear(ctx context.Context, pattern string) error {
mc.mu.Lock()
defer mc.mu.Unlock()
// Simple pattern matching for memory cache
for key := range mc.store {
if matchesPattern(key, pattern) {
delete(mc.store, key)
}
}
return nil
}
func (mc *MemoryCache) cleanup() {
ticker := time.NewTicker(mc.ttl)
defer ticker.Stop()
for range ticker.C {
mc.mu.Lock()
now := time.Now()
for key, entry := range mc.store {
if now.After(entry.expiration) {
delete(mc.store, key)
}
}
mc.mu.Unlock()
}
}
// Cache errors
var (
ErrCacheMiss = fmt.Errorf("cache miss")
ErrCacheFull = fmt.Errorf("cache full")
)
🔄 Advanced Caching Patterns
Cache-Aside Pattern
Cache-aside pattern configuration
cache_aside: #cache("""
user_cache -> Cache-aside for user data
strategy: "cache_aside"
ttl: 30m
key_pattern: "user:{id}"
storage: "redis"
fallback: "database"
invalidation: "on_update"
post_cache -> Cache-aside for post data
strategy: "cache_aside"
ttl: 1h
key_pattern: "post:{id}"
storage: "redis"
fallback: "database"
invalidation: "on_update"
compression: true
""")
Write-Through Pattern
Write-through pattern configuration
write_through: #cache("""
config_cache -> Write-through for configuration
strategy: "write_through"
ttl: 24h
key_pattern: "config:{key}"
storage: "redis"
primary: "database"
invalidation: "manual"
settings_cache -> Write-through for user settings
strategy: "write_through"
ttl: 1h
key_pattern: "settings:{user_id}"
storage: "redis"
primary: "database"
invalidation: "on_update"
""")
Cache-Only Pattern
Cache-only pattern configuration
cache_only: #cache("""
session_cache -> Cache-only for sessions
strategy: "cache_only"
ttl: 24h
key_pattern: "session:{id}"
storage: "redis"
invalidation: "on_logout"
security: "encrypted"
temp_cache -> Cache-only for temporary data
strategy: "cache_only"
ttl: 5m
key_pattern: "temp:{id}"
storage: "memory"
invalidation: "time_based"
""")
🛡️ Cache Security
Cache Security Configuration
Cache security configuration
cache_security: #cache("""
encryption -> Cache data encryption
algorithm: "AES-256-GCM"
key: #env("CACHE_ENCRYPTION_KEY")
enabled: true
access_control -> Cache access control
authentication: true
authorization: true
roles: ["admin", "cache_manager"]
data_validation -> Cache data validation
schema_validation: true
size_limits: true
max_size: 1MB
allowed_types: ["string", "number", "object"]
""")
Go Cache Security Implementation
package securityimport (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
)
// Encrypted cache wrapper
type EncryptedCache struct {
cache Cache
key []byte
gcm cipher.AEAD
}
func NewEncryptedCache(cache Cache, key string) (*EncryptedCache, error) {
// Decode key
decodedKey, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return nil, fmt.Errorf("invalid encryption key: %v", err)
}
// Create cipher
block, err := aes.NewCipher(decodedKey)
if err != nil {
return nil, fmt.Errorf("failed to create cipher: %v", err)
}
// Create GCM
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, fmt.Errorf("failed to create GCM: %v", err)
}
return &EncryptedCache{
cache: cache,
key: decodedKey,
gcm: gcm,
}, nil
}
func (ec *EncryptedCache) Get(ctx context.Context, key string) (interface{}, error) {
// Get encrypted data
encryptedData, err := ec.cache.Get(ctx, key)
if err != nil {
return nil, err
}
// Decrypt data
data, err := ec.decrypt(encryptedData.(string))
if err != nil {
return nil, fmt.Errorf("failed to decrypt cached data: %v", err)
}
// Deserialize
var value interface{}
if err := json.Unmarshal(data, &value); err != nil {
return nil, fmt.Errorf("failed to deserialize decrypted data: %v", err)
}
return value, nil
}
func (ec *EncryptedCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
// Serialize data
data, err := json.Marshal(value)
if err != nil {
return fmt.Errorf("failed to serialize data: %v", err)
}
// Encrypt data
encryptedData, err := ec.encrypt(data)
if err != nil {
return fmt.Errorf("failed to encrypt data: %v", err)
}
// Store encrypted data
return ec.cache.Set(ctx, key, encryptedData, ttl)
}
func (ec *EncryptedCache) Delete(ctx context.Context, key string) error {
return ec.cache.Delete(ctx, key)
}
func (ec *EncryptedCache) Clear(ctx context.Context, pattern string) error {
return ec.cache.Clear(ctx, pattern)
}
// Encrypt data
func (ec *EncryptedCache) encrypt(data []byte) (string, error) {
nonce := make([]byte, ec.gcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return "", err
}
ciphertext := ec.gcm.Seal(nonce, nonce, data, nil)
return base64.StdEncoding.EncodeToString(ciphertext), nil
}
// Decrypt data
func (ec *EncryptedCache) decrypt(encryptedData string) ([]byte, error) {
ciphertext, err := base64.StdEncoding.DecodeString(encryptedData)
if err != nil {
return nil, err
}
nonceSize := ec.gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, fmt.Errorf("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
return ec.gcm.Open(nil, nonce, ciphertext, nil)
}
⚡ Performance Optimization
Cache Performance Configuration
Cache performance configuration
cache_performance: #cache("""
connection_pooling -> Connection pooling
max_connections: 100
idle_connections: 10
connection_timeout: 30s
read_timeout: 5s
write_timeout: 5s
compression -> Data compression
enabled: true
algorithm: "gzip"
min_size: 1024
compression_level: 6
prefetching -> Cache prefetching
enabled: true
patterns: ["user:", "post:"]
batch_size: 100
interval: 5m
monitoring -> Cache monitoring
metrics_enabled: true
hit_rate_threshold: 0.8
miss_rate_alert: true
slow_query_threshold: 100ms
""")
Go Performance Implementation
package performanceimport (
"compress/gzip"
"bytes"
"context"
"io"
"sync"
"time"
)
// Compressed cache wrapper
type CompressedCache struct {
cache Cache
mu sync.RWMutex
}
func NewCompressedCache(cache Cache) *CompressedCache {
return &CompressedCache{cache: cache}
}
func (cc *CompressedCache) Get(ctx context.Context, key string) (interface{}, error) {
// Get compressed data
compressedData, err := cc.cache.Get(ctx, key)
if err != nil {
return nil, err
}
// Decompress data
data, err := cc.decompress(compressedData.([]byte))
if err != nil {
return nil, fmt.Errorf("failed to decompress cached data: %v", err)
}
// Deserialize
var value interface{}
if err := json.Unmarshal(data, &value); err != nil {
return nil, fmt.Errorf("failed to deserialize decompressed data: %v", err)
}
return value, nil
}
func (cc *CompressedCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
// Serialize data
data, err := json.Marshal(value)
if err != nil {
return fmt.Errorf("failed to serialize data: %v", err)
}
// Compress data if large enough
if len(data) > 1024 {
compressedData, err := cc.compress(data)
if err != nil {
return fmt.Errorf("failed to compress data: %v", err)
}
data = compressedData
}
// Store compressed data
return cc.cache.Set(ctx, key, data, ttl)
}
func (cc *CompressedCache) Delete(ctx context.Context, key string) error {
return cc.cache.Delete(ctx, key)
}
func (cc *CompressedCache) Clear(ctx context.Context, pattern string) error {
return cc.cache.Clear(ctx, pattern)
}
// Compress data
func (cc *CompressedCache) compress(data []byte) ([]byte, error) {
var buf bytes.Buffer
gz := gzip.NewWriter(&buf)
if _, err := gz.Write(data); err != nil {
return nil, err
}
if err := gz.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Decompress data
func (cc *CompressedCache) decompress(data []byte) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
defer gz.Close()
return io.ReadAll(gz)
}
// Cache prefetcher
type CachePrefetcher struct {
cache Cache
patterns []string
interval time.Duration
stopChan chan bool
}
func NewCachePrefetcher(cache Cache, patterns []string, interval time.Duration) *CachePrefetcher {
return &CachePrefetcher{
cache: cache,
patterns: patterns,
interval: interval,
stopChan: make(chan bool),
}
}
func (cp *CachePrefetcher) Start() {
ticker := time.NewTicker(cp.interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
cp.prefetch()
case <-cp.stopChan:
return
}
}
}
func (cp *CachePrefetcher) Stop() {
close(cp.stopChan)
}
func (cp *CachePrefetcher) prefetch() {
// Implementation depends on your data source
// This is a simplified example
for _, pattern := range cp.patterns {
// Fetch data that matches pattern
// and store in cache
}
}
🔧 Error Handling
Cache Error Configuration
Cache error handling configuration
cache_errors: #cache("""
connection_error -> Cache connection error
retry_attempts: 3
retry_delay: 1s
fallback: "memory"
log_level: error
timeout_error -> Cache timeout error
timeout: 5s
retry_attempts: 2
fallback: "database"
log_level: warn
storage_error -> Cache storage error
max_size: 100MB
eviction_policy: "lru"
fallback: "memory"
log_level: error
""")
Go Error Handler Implementation
package errorsimport (
"context"
"log"
"time"
)
// Cache error types
type CacheError struct {
Type string json:"type"
Message string json:"message"
Key string json:"key,omitempty"
Retries int json:"retries,omitempty"
}
// Cache error handlers
func HandleCacheError(err error, key string, retries int) {
cacheError := CacheError{
Type: "cache_error",
Message: err.Error(),
Key: key,
Retries: retries,
}
log.Printf("Cache error: %+v", cacheError)
// Record metrics
recordCacheError(cacheError)
// Alert if too many retries
if retries > 3 {
sendCacheAlert(cacheError)
}
}
// Retry wrapper for cache operations
func RetryCacheOperation(operation func() error, maxRetries int, delay time.Duration) error {
var lastErr error
for attempt := 0; attempt <= maxRetries; attempt++ {
if err := operation(); err == nil {
return nil
} else {
lastErr = err
log.Printf("Cache operation failed (attempt %d/%d): %v", attempt+1, maxRetries+1, err)
if attempt < maxRetries {
time.Sleep(delay)
}
}
}
return fmt.Errorf("cache operation failed after %d attempts: %v", maxRetries+1, lastErr)
}
// Fallback cache implementation
type FallbackCache struct {
primary Cache
fallback Cache
}
func NewFallbackCache(primary, fallback Cache) *FallbackCache {
return &FallbackCache{
primary: primary,
fallback: fallback,
}
}
func (fc *FallbackCache) Get(ctx context.Context, key string) (interface{}, error) {
// Try primary cache
value, err := fc.primary.Get(ctx, key)
if err == nil {
return value, nil
}
// Try fallback cache
value, err = fc.fallback.Get(ctx, key)
if err == nil {
// Store in primary cache for next time
go func() {
fc.primary.Set(context.Background(), key, value, 5*time.Minute)
}()
return value, nil
}
return nil, err
}
func (fc *FallbackCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
// Set in both caches
if err := fc.primary.Set(ctx, key, value, ttl); err != nil {
log.Printf("Failed to set in primary cache: %v", err)
}
if err := fc.fallback.Set(ctx, key, value, ttl); err != nil {
log.Printf("Failed to set in fallback cache: %v", err)
}
return nil
}
func (fc *FallbackCache) Delete(ctx context.Context, key string) error {
// Delete from both caches
fc.primary.Delete(ctx, key)
fc.fallback.Delete(ctx, key)
return nil
}
func (fc *FallbackCache) Clear(ctx context.Context, pattern string) error {
// Clear both caches
fc.primary.Clear(ctx, pattern)
fc.fallback.Clear(ctx, pattern)
return nil
}
🎯 Real-World Example
Complete Cache Configuration
cache-config.tsk - Complete cache configuration
Environment configuration
environment: #env("ENVIRONMENT", "development")
debug_mode: #env("DEBUG", "false")Cache strategies
strategies: #cache("""
# User data caching
user_cache -> User data caching
ttl: 30m
key_pattern: "user:{id}"
storage: "redis"
strategy: "cache_aside"
invalidation: "on_update"
compression: true
encryption: true
# Post data caching
post_cache -> Post data caching
ttl: 1h
key_pattern: "post:{id}"
storage: "redis"
strategy: "cache_aside"
invalidation: "on_update"
compression: true
# API response caching
api_cache -> API response caching
ttl: 5m
key_pattern: "api:{method}:{path}:{params}"
storage: "memory"
strategy: "cache_only"
invalidation: "time_based"
headers: ["ETag", "Last-Modified"]
# Session data caching
session_cache -> Session data caching
ttl: 24h
key_pattern: "session:{id}"
storage: "redis"
strategy: "cache_only"
invalidation: "on_logout"
encryption: true
security: "high"
# Configuration caching
config_cache -> Configuration caching
ttl: 24h
key_pattern: "config:{key}"
storage: "redis"
strategy: "write_through"
invalidation: "manual"
compression: true
""")Storage configuration
storage: #cache("""
redis -> Redis cache storage
url: #env("REDIS_URL")
db: 0
pool_size: 10
max_retries: 3
connection_timeout: 30s
read_timeout: 5s
write_timeout: 5s
memory -> In-memory cache storage
max_size: 1000
cleanup_interval: 5m
eviction_policy: "lru"
max_memory: 100MB
file -> File-based cache storage
path: "/tmp/cache"
max_size: 100MB
compression: true
cleanup_interval: 1h
""")Invalidation configuration
invalidation: #cache("""
on_update -> Invalidate on data update
events: ["user_updated", "post_updated", "config_updated"]
patterns: ["user:{id}", "post:{id}", "config:{key}"]
delay: 1s
time_based -> Time-based invalidation
interval: 1h
patterns: ["api:", "temp:"]
cleanup: true
manual -> Manual invalidation
endpoints: ["/cache/clear", "/cache/invalidate"]
patterns: ["*"]
authentication: true
authorization: ["admin"]
""")Performance configuration
performance: #cache("""
connection_pooling -> Connection pooling
max_connections: 100
idle_connections: 10
connection_timeout: 30s
read_timeout: 5s
write_timeout: 5s
compression -> Data compression
enabled: true
algorithm: "gzip"
min_size: 1024
compression_level: 6
threshold: 0.1
prefetching -> Cache prefetching
enabled: true
patterns: ["user:", "post:", "config:*"]
batch_size: 100
interval: 5m
concurrency: 5
monitoring -> Cache monitoring
metrics_enabled: true
hit_rate_threshold: 0.8
miss_rate_alert: true
slow_query_threshold: 100ms
memory_usage_alert: true
memory_threshold: 80%
""")Security configuration
security: #cache("""
encryption -> Cache data encryption
algorithm: "AES-256-GCM"
key: #env("CACHE_ENCRYPTION_KEY")
enabled: true
patterns: ["session:", "user:"]
access_control -> Cache access control
authentication: true
authorization: true
roles: ["admin", "cache_manager"]
endpoints: ["/cache/*"]
data_validation -> Cache data validation
schema_validation: true
size_limits: true
max_size: 1MB
allowed_types: ["string", "number", "object", "array"]
sanitization: true
""")Error handling
error_handling: #cache("""
connection_error -> Cache connection error
retry_attempts: 3
retry_delay: 1s
exponential_backoff: true
fallback: "memory"
log_level: error
alert: true
timeout_error -> Cache timeout error
timeout: 5s
retry_attempts: 2
fallback: "database"
log_level: warn
alert: false
storage_error -> Cache storage error
max_size: 100MB
eviction_policy: "lru"
fallback: "memory"
log_level: error
alert: true
data_corruption -> Cache data corruption
validation: true
checksum: true
fallback: "database"
log_level: error
alert: true
""")
Go Cache Application Implementation
package mainimport (
"fmt"
"log"
"net/http"
"github.com/tusklang/go-sdk"
"github.com/gorilla/mux"
)
type CacheConfig struct {
Environment string tsk:"environment"
DebugMode bool tsk:"debug_mode"
Strategies string tsk:"strategies"
Storage string tsk:"storage"
Invalidation string tsk:"invalidation"
Performance string tsk:"performance"
Security string tsk:"security"
ErrorHandling string tsk:"error_handling"
}
func main() {
// Load cache configuration
config := tusk.LoadConfig("cache-config.tsk")
var cacheConfig CacheConfig
if err := config.Unmarshal(&cacheConfig); err != nil {
log.Fatal("Failed to load cache config:", err)
}
// Create cache system from directives
cache := tusk.NewCacheSystem(cacheConfig)
// Create router
router := mux.NewRouter()
// Apply cache middleware
tusk.ApplyCacheMiddleware(router, cache)
// Setup routes
setupRoutes(router, cache)
// Start server
addr := fmt.Sprintf(":%s", #env("PORT", "8080"))
log.Printf("Starting cache server on %s in %s mode", addr, cacheConfig.Environment)
if err := http.ListenAndServe(addr, router); err != nil {
log.Fatal("Cache server failed:", err)
}
}
func setupRoutes(router mux.Router, cache tusk.CacheSystem) {
// Health check
router.HandleFunc("/health", healthHandler).Methods("GET")
router.HandleFunc("/metrics", metricsHandler).Methods("GET")
// Cache management endpoints
cacheRouter := router.PathPrefix("/cache").Subrouter()
cacheRouter.Use(authMiddleware)
cacheRouter.HandleFunc("/clear", cache.ClearHandler).Methods("POST")
cacheRouter.HandleFunc("/invalidate", cache.InvalidateHandler).Methods("POST")
cacheRouter.HandleFunc("/stats", cache.StatsHandler).Methods("GET")
cacheRouter.HandleFunc("/keys", cache.KeysHandler).Methods("GET")
// API routes with caching
api := router.PathPrefix("/api").Subrouter()
// User routes with caching
api.HandleFunc("/users/{id}", cache.WrapHandler(userHandler, "user_cache")).Methods("GET")
api.HandleFunc("/users", cache.WrapHandler(usersHandler, "user_cache")).Methods("GET")
// Post routes with caching
api.HandleFunc("/posts/{id}", cache.WrapHandler(postHandler, "post_cache")).Methods("GET")
api.HandleFunc("/posts", cache.WrapHandler(postsHandler, "post_cache")).Methods("GET")
// Configuration routes with caching
api.HandleFunc("/config/{key}", cache.WrapHandler(configHandler, "config_cache")).Methods("GET", "PUT")
}
🎯 Best Practices
1. Use Appropriate Cache Strategies
Choose the right cache strategy for each use case
strategy_selection: #cache("""
# Cache-aside for frequently read, rarely updated data
user_profile -> "user:{id}" -> 30m -> cache_aside
# Write-through for critical data that must be consistent
user_settings -> "settings:{user_id}" -> 1h -> write_through
# Cache-only for temporary data
session_data -> "session:{id}" -> 24h -> cache_only
""")
2. Implement Proper Error Handling
// Comprehensive cache error handling
func handleCacheError(err error, operation string, key string) {
log.Printf("Cache %s error for key %s: %v", operation, key, err)
// Record metrics
recordCacheError(operation, key, err)
// Use fallback if available
if fallbackCache != nil {
log.Printf("Using fallback cache for key %s", key)
// Implement fallback logic
}
// Alert on critical errors
if isCriticalError(err) {
sendCacheAlert(operation, key, err)
}
}
3. Use Environment-Specific Configuration
Different cache settings for different environments
environment_cache: #if(
#env("ENVIRONMENT") == "production",
#cache("""
ttl_multiplier: 1
compression: true
encryption: true
monitoring: true
"""),
#cache("""
ttl_multiplier: 0.1
compression: false
encryption: false
monitoring: false
""")
)
4. Monitor Cache Performance
// Cache performance monitoring
func monitorCachePerformance(operation string, startTime time.Time, hit bool) {
duration := time.Since(startTime)
// Record metrics
metrics := map[string]interface{}{
"operation": operation,
"duration": duration.Milliseconds(),
"hit": hit,
"timestamp": time.Now(),
}
if err := recordCacheMetrics(metrics); err != nil {
log.Printf("Failed to record cache metrics: %v", err)
}
// Alert on slow operations
if duration > 100*time.Millisecond {
log.Printf("Slow cache operation: %s took %v", operation, duration)
}
// Alert on low hit rates
if !hit && getHitRate() < 0.8 {
log.Printf("Low cache hit rate: %.2f%%", getHitRate()*100)
}
}
🎯 Summary
Cache directives in TuskLang provide a powerful, declarative way to define caching systems. They enable:
- Declarative cache configuration that is easy to understand and maintain - Flexible cache strategies including cache-aside, write-through, and cache-only - Comprehensive storage options including Redis, memory, and file-based storage - Built-in security features including encryption and access control - Performance optimization with compression, prefetching, and connection pooling
The Go SDK seamlessly integrates cache directives with existing Go caching libraries, making them feel like native Go features while providing the power and flexibility of TuskLang's directive system.
Next: Explore rate limit directives, monitoring directives, and other specialized directive types in the following guides.