Cache
λ Cosmos provides a caching abstraction through the contract.Cache interface with two built-in implementations: in-memory and Redis.
type Cache interface { Get(ctx context.Context, key string) (any, error) Put(ctx context.Context, key string, value any, ttl time.Duration) error Delete(ctx context.Context, key string) error Has(ctx context.Context, key string) (bool, error) Pull(ctx context.Context, key string) (any, error) Forever(ctx context.Context, key string, value any) error Increment(ctx context.Context, key string, by int64) (int64, error) Decrement(ctx context.Context, key string, by int64) (int64, error) Remember(ctx context.Context, key string, ttl time.Duration, compute func() (any, error)) (any, error) RememberForever(ctx context.Context, key string, compute func() (any, error)) (any, error)}When a key is not found, Get and Pull return contract.ErrCacheKeyNotFound:
val, err := cache.Get(ctx, "user:42")if errors.Is(err, contract.ErrCacheKeyNotFound) { // key does not exist or has expired}Memory Cache
Section titled “Memory Cache”An in-memory cache suitable for development, testing, and single-instance applications:
import "github.com/studiolambda/cosmos/framework/cache"
c := cache.NewMemory(5*time.Minute, 10*time.Minute)The two parameters are:
- Default expiration — TTL applied when using
Putwith a zero duration. - Cleanup interval — How often expired items are removed from memory.
Redis Cache
Section titled “Redis Cache”A Redis-backed cache for distributed applications:
import "github.com/studiolambda/cosmos/framework/cache"
c := cache.NewRedis(&cache.RedisOptions{ Addr: "localhost:6379", Password: "", DB: 0,})Or wrap an existing *redis.Client:
c := cache.NewRedisFrom(existingRedisClient)Common Operations
Section titled “Common Operations”Get / Put
Section titled “Get / Put”// Store a value for 10 minuteserr := cache.Put(ctx, "user:42", user, 10*time.Minute)
// Retrieve itval, err := cache.Get(ctx, "user:42")Forever
Section titled “Forever”Store a value that never expires:
err := cache.Forever(ctx, "config:site_name", "My App")Check existence without retrieving:
exists, err := cache.Has(ctx, "user:42")Delete
Section titled “Delete”Remove a cached value:
err := cache.Delete(ctx, "user:42")Retrieve and remove in one atomic operation:
val, err := cache.Pull(ctx, "one-time-token:abc123")// val is returned, key is deletedIncrement / Decrement
Section titled “Increment / Decrement”Atomically modify integer values:
newVal, err := cache.Increment(ctx, "page_views", 1)newVal, err := cache.Decrement(ctx, "remaining_quota", 1)The key must already exist or contract.ErrCacheKeyNotFound is returned (for the memory implementation). The Redis implementation creates the key if it doesn’t exist.
Remember / RememberForever
Section titled “Remember / RememberForever”Get a cached value or compute and store it if missing:
val, err := cache.Remember(ctx, "user:42", 10*time.Minute, func() (any, error) { return db.FindUser(ctx, 42)})This is the most common caching pattern — it avoids the check-then-set race condition by combining the operations:
// Without Remember (race condition possible):val, err := cache.Get(ctx, key)if errors.Is(err, contract.ErrCacheKeyNotFound) { val, err = expensiveComputation() cache.Put(ctx, key, val, ttl)}
// With Remember (atomic):val, err := cache.Remember(ctx, key, ttl, expensiveComputation)RememberForever works the same but stores the value with no expiration.