cache

package
v1.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

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

Examples

Constants

This section is empty.

Variables

View Source
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

func Invalidate(s store.KV, key string) error

Invalidate removes the exact cache entry for the given key.

func InvalidatePrefix

func InvalidatePrefix(s store.KV, prefix string) error

InvalidatePrefix removes every cache entry whose key begins with prefix. Returns ErrNotSupported if the store does not implement store.PrefixDeleter.

func New

func New(config ...Config) celeris.HandlerFunc

New returns a cache middleware.

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,
	}
}
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,
	}
}

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) Get

func (m *MemoryStore) Get(_ context.Context, key string) ([]byte, error)

Get implements store.KV. Moves the accessed entry to the MRU end.

func (*MemoryStore) Scan

func (m *MemoryStore) Scan(_ context.Context, prefix string) ([]string, error)

Scan implements store.Scanner.

func (*MemoryStore) Set

func (m *MemoryStore) Set(_ context.Context, key string, value []byte, ttl time.Duration) error

Set implements store.KV. Evicts the LRU entry when the shard is over capacity.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL