Documentation
¶
Overview ¶
Package cache is part of the GoFastr framework. See https://github.com/DonaldMurillo/gofastr for documentation.
Index ¶
- Constants
- Variables
- func CacheMiddleware(cache Cache, ttl time.Duration) func(http.Handler) http.Handler
- func CacheMiddlewareWithLimit(cache Cache, ttl time.Duration, maxBodyBytes int) func(http.Handler) http.Handler
- func GetOrSet(ctx context.Context, c Cache, key string, ttl time.Duration, dest any, ...) error
- type Cache
- type Item
- type Loader
- type MemoryCache
- func (mc *MemoryCache) Clear(_ context.Context) error
- func (mc *MemoryCache) Close()
- func (mc *MemoryCache) Delete(_ context.Context, key string) error
- func (mc *MemoryCache) Exists(_ context.Context, key string) (bool, error)
- func (mc *MemoryCache) Get(_ context.Context, key string, dest any) error
- func (mc *MemoryCache) Len() int
- func (mc *MemoryCache) Set(_ context.Context, key string, value any, ttl time.Duration) error
- type Option
- type RedisCache
- func (rc *RedisCache) Clear(ctx context.Context) error
- func (rc *RedisCache) Delete(ctx context.Context, key string) error
- func (rc *RedisCache) Exists(ctx context.Context, key string) (bool, error)
- func (rc *RedisCache) Get(ctx context.Context, key string, dest any) error
- func (rc *RedisCache) Set(ctx context.Context, key string, value any, ttl time.Duration) error
- type RedisClient
Constants ¶
const DefaultMaxCacheableBytes = 8 << 20
CacheMiddleware returns an HTTP middleware that caches GET responses using the provided Cache implementation. The X-Cache response header is set to "HIT" or "MISS" accordingly.
The middleware is conservative and refuses to cache responses that carry user-specific data or that the origin marks as uncacheable:
- Requests other than GET are passed through untouched.
- Requests carrying a Range header are passed through untouched and never cached: the key does not encode the Range, so a partial (206) body must not be allowed to collide with the full variant.
- The cache key includes the request authority (Host) so distinct virtual hosts sharing one Cache do not serve each other's content.
- Requests with Authorization or Cookie headers are not served from or written to the cache by default (RFC 9111 §3.5 / §3 default).
- Requests with Cache-Control: no-cache or no-store bypass the stored variant and force a fresh origin fetch (no-store also skips writing the response back into the cache).
- Responses with Set-Cookie or with Cache-Control containing private, no-store, or no-cache are never stored.
- Responses with non-2xx/3xx status (i.e. 4xx and 5xx) are never stored. Partial-content (206) responses, or any response carrying a Content-Range header, are likewise never stored.
- Responses carrying a Vary header are stored under a key that includes the values of every listed request header so different variants do not collide. A Vary: * response is treated as uncacheable and is never stored (RFC 9111 §4.1).
DefaultMaxCacheableBytes caps how large a response CacheMiddleware will buffer for caching (8 MiB). Larger responses stream straight to the client and are not cached, so a single huge response can't pin unbounded memory.
Variables ¶
var ErrCacheMiss = errors.New("cache: key not found")
ErrCacheMiss is returned when a key is not found in the cache.
Functions ¶
func CacheMiddleware ¶
func CacheMiddlewareWithLimit ¶
func CacheMiddlewareWithLimit(cache Cache, ttl time.Duration, maxBodyBytes int) func(http.Handler) http.Handler
CacheMiddlewareWithLimit is CacheMiddleware with an explicit cap on the response size that may be buffered for caching. A response exceeding maxBodyBytes is streamed to the client and never stored. Pass 0 for unbounded buffering (the pre-cap behaviour — not recommended in production).
func GetOrSet ¶
func GetOrSet(ctx context.Context, c Cache, key string, ttl time.Duration, dest any, loader Loader) error
GetOrSet returns the cached value for key, deserialized into dest. On a miss it invokes loader exactly once — even when many goroutines miss the same key concurrently — stores the result with the given TTL, and shares it with all waiters. A loader error is propagated and never cached.
dest must be a non-nil pointer. The loader's returned value is round-tripped through the cache (JSON) so the value written into dest is the cached form.
Types ¶
type Cache ¶
type Cache interface {
// Get retrieves a value from the cache and deserializes it into dest.
// Returns ErrCacheMiss if the key does not exist or has expired.
Get(ctx context.Context, key string, dest any) error
// Set stores a value in the cache with the given TTL.
// A TTL of 0 means the entry uses the default TTL.
Set(ctx context.Context, key string, value any, ttl time.Duration) error
// Delete removes a key from the cache.
Delete(ctx context.Context, key string) error
// Exists checks whether a key exists in the cache and has not expired.
Exists(ctx context.Context, key string) (bool, error)
// Clear removes all entries from the cache.
Clear(ctx context.Context) error
}
Cache defines the interface for cache implementations.
type MemoryCache ¶
type MemoryCache struct {
// contains filtered or unexported fields
}
MemoryCache is an in-memory Cache implementation backed by a map with read-write mutex for thread safety. It supports TTL-based expiration with lazy eviction on access and an optional background cleanup goroutine.
func NewMemoryCache ¶
func NewMemoryCache(opts ...Option) *MemoryCache
NewMemoryCache creates a new in-memory cache. The background cleanup goroutine starts automatically when a cleanup interval is configured (default: 1 minute). Call Close to stop it.
func (*MemoryCache) Clear ¶
func (mc *MemoryCache) Clear(_ context.Context) error
Clear removes all entries from the cache.
func (*MemoryCache) Close ¶
func (mc *MemoryCache) Close()
Close stops the background cleanup goroutine.
func (*MemoryCache) Delete ¶
func (mc *MemoryCache) Delete(_ context.Context, key string) error
Delete removes a key from the cache.
func (*MemoryCache) Len ¶
func (mc *MemoryCache) Len() int
Len reports the number of live entries currently held. Primarily useful for tests and for observing eviction on a bounded cache.
type Option ¶
type Option func(*config)
Option configures a cache instance.
func WithCleanupInterval ¶
WithCleanupInterval sets the interval for the background cleanup goroutine in MemoryCache. Defaults to 1 minute if not set.
func WithMaxEntries ¶
WithMaxEntries bounds a MemoryCache to at most n live entries. Once the cap is reached, inserting a new key evicts the least-recently-used entry (LRU).
The zero-config default is UNBOUNDED (n <= 0), preserving historical behavior. Set this whenever cache keys are influenced by untrusted input to avoid unbounded memory growth (OOM/DoS). It has no effect on RedisCache, where eviction is governed by the Redis server's own maxmemory policy.
func WithPrefix ¶
WithPrefix sets a key prefix for all cache operations.
type RedisCache ¶
type RedisCache struct {
// contains filtered or unexported fields
}
RedisCache implements the Cache interface backed by a Redis store.
func NewRedisCache ¶
func NewRedisCache(client RedisClient, opts ...Option) *RedisCache
NewRedisCache creates a new Redis-backed cache.
func (*RedisCache) Clear ¶
func (rc *RedisCache) Clear(ctx context.Context) error
Clear removes all keys from the current Redis database.
func (*RedisCache) Delete ¶
func (rc *RedisCache) Delete(ctx context.Context, key string) error
Delete removes a key from Redis.
type RedisClient ¶
type RedisClient interface {
// Get retrieves the string value for a key. Should return a redis nil
// error when the key does not exist.
Get(ctx context.Context, key string) (string, error)
// Set stores a string value with an optional expiration. A TTL of 0
// means no expiration.
Set(ctx context.Context, key string, value string, ttl time.Duration) error
// Del removes one or more keys.
Del(ctx context.Context, keys ...string) error
// Exists checks whether a key exists.
Exists(ctx context.Context, key string) (bool, error)
// FlushDB removes all keys from the current database.
FlushDB(ctx context.Context) error
}
RedisClient defines the minimal interface needed for a Redis cache backend. No specific Redis library is imported; implement this interface with your preferred Redis client (e.g. go-redis, redigo, etc.).