Documentation
¶
Overview ¶
Package cache provides a pluggable HTTP response cache middleware.
Overview ¶
The cache buffers the handler response (status + filtered headers + body), encodes it via the versioned wire format in middleware/store, and persists the result under a request-derived key. Subsequent requests that produce the same key skip the handler and replay the stored response.
Backends ¶
Any store.KV implementation works. The default NewMemoryStore provides a sharded LRU with per-shard mutexes; store.MemoryKV is also compatible but does not implement LRU eviction. For multi- instance deployments, use middleware/session/redisstore.New with a cache-specific prefix.
Singleflight ¶
When [Config.Singleflight] is true (default), concurrent requests that miss on the same key coalesce: one handler runs, the rest wait for its result. Turn this off when handlers have side effects that must run per-request.
Cache-Control ¶
With [Config.RespectCacheControl] (default: true), the middleware honors directives on the handler's response:
- no-store, private → the response is not cached
- max-age=N → TTL is capped at min(Config.TTL, N seconds)
Invalidation ¶
- Invalidate removes a single computed key
- InvalidatePrefix removes every key with the given prefix (requires store.PrefixDeleter)
Index ¶
- Variables
- func Invalidate(s store.KV, key string) error
- func InvalidatePrefix(s store.KV, prefix string) error
- func New(config ...Config) celeris.HandlerFunc
- type Config
- type MemoryStore
- func (m *MemoryStore) Close()
- func (m *MemoryStore) Delete(_ context.Context, key string) error
- func (m *MemoryStore) DeletePrefix(_ context.Context, prefix string) error
- func (m *MemoryStore) Get(_ context.Context, key string) ([]byte, error)
- func (m *MemoryStore) Scan(_ context.Context, prefix string) ([]string, error)
- func (m *MemoryStore) Set(_ context.Context, key string, value []byte, ttl time.Duration) error
- type MemoryStoreConfig
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotSupported = errors.New("cache: store does not support this operation")
ErrNotSupported is returned by InvalidatePrefix when the given store does not implement the required extension interface.
Functions ¶
func Invalidate ¶
Invalidate removes the exact cache entry for the given key.
func InvalidatePrefix ¶
InvalidatePrefix removes every cache entry whose key begins with prefix. Returns ErrNotSupported if the store does not implement store.PrefixDeleter.
Types ¶
type Config ¶
type Config struct {
// Store is the cache backend. Default: [NewMemoryStore].
Store store.KV
// TTL is the default cache entry lifetime. Default: 1 minute.
// Per-response Cache-Control: max-age directives, when respected,
// cap the effective TTL to min(TTL, max-age).
TTL time.Duration
// KeyGenerator derives the cache key from a request. When nil, the
// default uses method + path + sorted query string + values of every
// header listed in [VaryHeaders].
KeyGenerator func(*celeris.Context) string
// Singleflight coalesces concurrent cache-miss requests for the same
// key so only one handler invocation runs; waiters reuse the
// resulting response. Default: true.
Singleflight bool
// Methods lists HTTP methods eligible for caching. Default: GET, HEAD.
// Methods not in this list pass through without interacting with
// the cache.
Methods []string
// StatusFilter decides whether a computed response should be stored.
// When nil, only 2xx responses are cached.
StatusFilter func(status int) bool
// VaryHeaders are included in the default cache key. Callers who
// provide their own [KeyGenerator] can ignore this field.
VaryHeaders []string
// HeaderName is the response header populated with "HIT" or "MISS".
// Default: "X-Cache". Set to "" to disable.
HeaderName string
// MaxBodyBytes caps the response body size eligible for caching.
// Responses larger than this pass through uncached. Default: 1 MiB.
MaxBodyBytes int
// IncludeHeaders, when non-empty, whitelists response headers that
// are stored alongside the body. When nil, all response headers
// are stored except those in [ExcludeHeaders] (default: Set-Cookie).
IncludeHeaders []string
// ExcludeHeaders, when non-empty, is subtracted from the stored
// header set after applying [IncludeHeaders]. Default: "set-cookie".
ExcludeHeaders []string
// RespectCacheControl, when true (default), honors the response's
// Cache-Control directive:
// - no-store or private → skip caching
// - max-age=N → cap TTL to min(cfg.TTL, N)
RespectCacheControl bool
// Skip defines a function to skip this middleware for certain
// requests.
Skip func(*celeris.Context) bool
// SkipPaths lists paths to skip (exact match).
SkipPaths []string
}
Config defines the cache middleware configuration.
Example ¶
ExampleConfig — the minimum useful configuration: an in-memory LRU store with a 60-second TTL. Drop the resulting middleware on a router with `app.Use(cache.New(cfg))`. Subsequent matching requests within the TTL skip the handler chain and replay the cached response.
package main
import (
"time"
"github.com/goceleris/celeris/middleware/cache"
"github.com/goceleris/celeris/middleware/store"
)
func main() {
_ = cache.Config{
Store: store.NewMemoryKV(),
TTL: 60 * time.Second,
}
}
Output:
Example (RedisStore) ¶
ExampleConfig_redisStore demonstrates wiring a Redis-backed store via any store.KV implementation (the project ships store.NewMemoryKV; the same shape applies to redis / postgres / memcached adapters under middleware/store).
package main
import (
"time"
"github.com/goceleris/celeris/middleware/cache"
"github.com/goceleris/celeris/middleware/store"
)
func main() {
// Stand-in: any store.KV may be assigned here.
kv := store.NewMemoryKV()
_ = cache.Config{
Store: kv,
TTL: 30 * time.Second,
RespectCacheControl: true,
Singleflight: true,
}
}
Output:
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore is an in-memory, sharded LRU cache. It implements store.KV, store.PrefixDeleter, and store.Scanner.
func NewMemoryStore ¶
func NewMemoryStore(config ...MemoryStoreConfig) *MemoryStore
NewMemoryStore returns a new in-memory cache store.
func (*MemoryStore) Close ¶
func (m *MemoryStore) Close()
Close stops the cleanup goroutine. Safe to call multiple times.
func (*MemoryStore) Delete ¶
func (m *MemoryStore) Delete(_ context.Context, key string) error
Delete implements store.KV.
func (*MemoryStore) DeletePrefix ¶
func (m *MemoryStore) DeletePrefix(_ context.Context, prefix string) error
DeletePrefix implements store.PrefixDeleter.
func (*MemoryStore) Scan ¶
Scan implements store.Scanner.
type MemoryStoreConfig ¶
type MemoryStoreConfig struct {
// Shards is the number of lock shards. Default: runtime.NumCPU(),
// rounded up to the next power of two.
Shards int
// MaxEntries is the total cache entry count across all shards.
// Zero means unlimited. Per-shard capacity is MaxEntries/Shards
// rounded up.
MaxEntries int
// CleanupInterval is how often expired entries are evicted.
// Default: 1 minute.
CleanupInterval time.Duration
// CleanupContext, when set, stops the cleanup goroutine when the
// context is cancelled.
CleanupContext context.Context
}
MemoryStoreConfig configures the in-memory cache store.