Documentation
¶
Index ¶
- Constants
- Variables
- func IsDebugLogging() bool
- func SetDebugLogging(b bool)
- func SetDefaultMetrics(m *CacheMetrics)
- func SetLogger(log *logger.Logger)
- type Cache
- type CacheConfig
- func (c *CacheConfig) Validate() *CacheConfig
- func (c *CacheConfig) WithCleanupInterval(interval time.Duration) *CacheConfig
- func (c *CacheConfig) WithMaxSize(size int64) *CacheConfig
- func (c *CacheConfig) WithStaleMapTTL(ttl time.Duration) *CacheConfig
- func (c *CacheConfig) WithTTL(ttl time.Duration) *CacheConfig
- type CacheControl
- type CacheMetrics
- func (m *CacheMetrics) RecordCacheEviction(reason string)
- func (m *CacheMetrics) RecordCacheHit(method string)
- func (m *CacheMetrics) RecordCacheMiss(method string)
- func (m *CacheMetrics) RecordCacheSkip()
- func (m *CacheMetrics) RecordCleanupDuration(durationSeconds float64)
- func (m *CacheMetrics) RecordRetrieveOperation(found bool)
- func (m *CacheMetrics) RecordStoreOperation(success bool)
- func (m *CacheMetrics) RecordUpstreamDuration(method string, status int, durationSeconds float64)
- func (m *CacheMetrics) RecordUpstreamError(errorType string)
- func (m *CacheMetrics) SetCacheItemCount(count int)
- func (m *CacheMetrics) SetCacheSize(sizeBytes int64)
- func (m *CacheMetrics) SetCacheStaleCount(count int)
- func (m *CacheMetrics) UpdateCacheStats(stats CacheStats)
- type CacheStats
- type CleanupResult
- type ExtendedCache
- type Handler
- type HandlerOptions
- type Header
- type Key
- type ReadSeekCloser
- type Resource
- func (r *Resource) Age() (time.Duration, error)
- func (r *Resource) DateAfter(d time.Time) bool
- func (r *Resource) Expires() (time.Time, error)
- func (r *Resource) HasExplicitExpiration() bool
- func (r *Resource) HasValidators() bool
- func (r *Resource) Header() http.Header
- func (r *Resource) HeuristicFreshness() time.Duration
- func (r *Resource) IsNonErrorStatus() bool
- func (r *Resource) IsStale() bool
- func (r *Resource) LastModified() time.Time
- func (r *Resource) MarkStale()
- func (r *Resource) MaxAge(shared bool) (time.Duration, error)
- func (r *Resource) MustValidate(shared bool) bool
- func (r *Resource) ReceivedAfter(d time.Time) bool
- func (r *Resource) RemovePrivateHeaders()
- func (r *Resource) SetStoredAt(t time.Time)
- func (r *Resource) Status() int
- func (r *Resource) StoredAfter(d time.Time) bool
- func (r *Resource) Via() string
- type Validator
Constants ¶
const ( CacheHeader = "X-Cache" ProxyDateHeader = "Proxy-Date" )
const (
CacheControlHeader = "Cache-Control"
)
const DefaultCacheTTL = 7 * 24 * time.Hour
DefaultCacheTTL is the default TTL for cached items (7 days)
const DefaultCleanupInterval = 1 * time.Hour
DefaultCleanupInterval is the default interval for cache cleanup (1 hour)
const DefaultMaxCacheSize int64 = 10 * 1024 * 1024 * 1024
DefaultMaxCacheSize is the default maximum cache size (10 GB)
const DefaultStaleMapTTL = 24 * time.Hour
DefaultStaleMapTTL is the default TTL for stale map entries (24 hours)
Variables ¶
var Clock = func() time.Time { return time.Now().UTC() }
var ErrNotFoundInCache = errors.New("not found in cache")
Returned when a resource doesn't exist
var Writes sync.WaitGroup
Functions ¶
func IsDebugLogging ¶
func IsDebugLogging() bool
IsDebugLogging returns whether debug messages are logged. Safe for concurrent use.
func SetDebugLogging ¶
func SetDebugLogging(b bool)
SetDebugLogging sets whether debug messages are logged. Safe for concurrent use.
func SetDefaultMetrics ¶
func SetDefaultMetrics(m *CacheMetrics)
SetDefaultMetrics sets the default metrics instance (e.g. for tests).
Types ¶
type Cache ¶
type Cache interface {
Header(key string) (Header, error)
Store(res *Resource, keys ...string) error
Retrieve(key string) (*Resource, error)
Invalidate(keys ...string)
Freshen(res *Resource, keys ...string) error
}
func NewDiskCache ¶
NewDiskCache returns a disk-backed cache
func NewMemoryCache ¶
func NewMemoryCache() Cache
NewMemoryCache returns an ephemeral cache in memory
func NewVFSCache ¶
NewVFSCache returns a cache backend off the provided VFS
type CacheConfig ¶
type CacheConfig struct {
// MaxSize is the maximum size of the cache in bytes.
// When exceeded, the oldest items will be evicted (LRU).
// Set to 0 to disable size-based eviction.
MaxSize int64
// TTL is the time-to-live for cached items.
// Items older than this will be evicted during cleanup.
// Set to 0 to disable TTL-based eviction.
TTL time.Duration
// CleanupInterval is the interval between automatic cleanup runs.
// Set to 0 to disable automatic cleanup.
CleanupInterval time.Duration
// StaleMapTTL is the TTL for stale map entries.
// Stale entries older than this will be removed.
StaleMapTTL time.Duration
}
CacheConfig holds configuration for cache behavior
func DefaultCacheConfig ¶
func DefaultCacheConfig() *CacheConfig
DefaultCacheConfig returns a CacheConfig with sensible defaults
func (*CacheConfig) Validate ¶
func (c *CacheConfig) Validate() *CacheConfig
Validate validates the configuration and applies defaults where needed
func (*CacheConfig) WithCleanupInterval ¶
func (c *CacheConfig) WithCleanupInterval(interval time.Duration) *CacheConfig
WithCleanupInterval sets the cleanup interval
func (*CacheConfig) WithMaxSize ¶
func (c *CacheConfig) WithMaxSize(size int64) *CacheConfig
WithMaxSize sets the maximum cache size
func (*CacheConfig) WithStaleMapTTL ¶
func (c *CacheConfig) WithStaleMapTTL(ttl time.Duration) *CacheConfig
WithStaleMapTTL sets the stale map TTL
func (*CacheConfig) WithTTL ¶
func (c *CacheConfig) WithTTL(ttl time.Duration) *CacheConfig
WithTTL sets the TTL for cached items
type CacheControl ¶
func ParseCacheControl ¶
func ParseCacheControl(input string) (CacheControl, error)
func ParseCacheControlHeaders ¶
func ParseCacheControlHeaders(h http.Header) (CacheControl, error)
func (CacheControl) Add ¶
func (cc CacheControl) Add(key, val string)
func (CacheControl) Has ¶
func (cc CacheControl) Has(key string) bool
func (CacheControl) String ¶
func (cc CacheControl) String() string
type CacheMetrics ¶
type CacheMetrics struct {
// CacheHits tracks the number of cache hits
CacheHits *prometheus.CounterVec
// CacheMisses tracks the number of cache misses
CacheMisses *prometheus.CounterVec
// CacheSkips tracks the number of cache skips (non-cacheable requests)
CacheSkips prometheus.Counter
// UpstreamDuration tracks the duration of upstream requests
UpstreamDuration *prometheus.HistogramVec
// CacheSizeBytes tracks the current cache size in bytes (gauge)
CacheSizeBytes prometheus.Gauge
// CacheItemCount tracks the current number of cached items (gauge)
CacheItemCount prometheus.Gauge
// CacheStaleCount tracks the current number of stale map entries (gauge)
CacheStaleCount prometheus.Gauge
// UpstreamErrors tracks the number of upstream errors
UpstreamErrors *prometheus.CounterVec
// CacheStoreOperations tracks cache store operations
CacheStoreOperations *prometheus.CounterVec
// CacheRetrieveOperations tracks cache retrieve operations
CacheRetrieveOperations *prometheus.CounterVec
// CacheEvictions tracks the number of cache evictions
CacheEvictions *prometheus.CounterVec
// CacheCleanupDuration tracks the duration of cleanup operations
CacheCleanupDuration prometheus.Histogram
}
CacheMetrics holds Prometheus metrics for cache operations
func GetDefaultMetrics ¶
func GetDefaultMetrics() *CacheMetrics
GetDefaultMetrics returns the current default metrics instance (nil until initialized).
func NewCacheMetrics ¶
func NewCacheMetrics(registry *metrics.Registry) *CacheMetrics
NewCacheMetrics creates and registers cache metrics with the given registry
func (*CacheMetrics) RecordCacheEviction ¶
func (m *CacheMetrics) RecordCacheEviction(reason string)
RecordCacheEviction records a cache eviction
func (*CacheMetrics) RecordCacheHit ¶
func (m *CacheMetrics) RecordCacheHit(method string)
RecordCacheHit records a cache hit
func (*CacheMetrics) RecordCacheMiss ¶
func (m *CacheMetrics) RecordCacheMiss(method string)
RecordCacheMiss records a cache miss
func (*CacheMetrics) RecordCacheSkip ¶
func (m *CacheMetrics) RecordCacheSkip()
RecordCacheSkip records a cache skip
func (*CacheMetrics) RecordCleanupDuration ¶
func (m *CacheMetrics) RecordCleanupDuration(durationSeconds float64)
RecordCleanupDuration records the duration of a cleanup operation
func (*CacheMetrics) RecordRetrieveOperation ¶
func (m *CacheMetrics) RecordRetrieveOperation(found bool)
RecordRetrieveOperation records a cache retrieve operation
func (*CacheMetrics) RecordStoreOperation ¶
func (m *CacheMetrics) RecordStoreOperation(success bool)
RecordStoreOperation records a cache store operation
func (*CacheMetrics) RecordUpstreamDuration ¶
func (m *CacheMetrics) RecordUpstreamDuration(method string, status int, durationSeconds float64)
RecordUpstreamDuration records the duration of an upstream request
func (*CacheMetrics) RecordUpstreamError ¶
func (m *CacheMetrics) RecordUpstreamError(errorType string)
RecordUpstreamError records an upstream error
func (*CacheMetrics) SetCacheItemCount ¶
func (m *CacheMetrics) SetCacheItemCount(count int)
SetCacheItemCount sets the current number of cached items
func (*CacheMetrics) SetCacheSize ¶
func (m *CacheMetrics) SetCacheSize(sizeBytes int64)
SetCacheSize sets the current cache size in bytes
func (*CacheMetrics) SetCacheStaleCount ¶
func (m *CacheMetrics) SetCacheStaleCount(count int)
SetCacheStaleCount sets the current number of stale map entries
func (*CacheMetrics) UpdateCacheStats ¶
func (m *CacheMetrics) UpdateCacheStats(stats CacheStats)
UpdateCacheStats updates all cache gauge metrics from stats
type CacheStats ¶
type CacheStats struct {
// TotalSize is the total size of cached items in bytes
TotalSize int64
// ItemCount is the number of cached items
ItemCount int
// StaleCount is the number of stale map entries
StaleCount int
// HitCount is the number of cache hits
HitCount int64
// MissCount is the number of cache misses
MissCount int64
}
CacheStats holds cache statistics
type CleanupResult ¶
type CleanupResult struct {
// RemovedItems is the number of items removed
RemovedItems int
// RemovedBytes is the number of bytes freed
RemovedBytes int64
// RemovedStaleEntries is the number of stale map entries removed
RemovedStaleEntries int
// Duration is how long the cleanup took
Duration time.Duration
}
CleanupResult holds the result of a cleanup operation
type ExtendedCache ¶
type ExtendedCache interface {
Cache
// Stats returns current cache statistics
Stats() CacheStats
// Cleanup runs a manual cleanup cycle
Cleanup() CleanupResult
// Purge removes all cached items
Purge() error
// Close stops the cache and cleanup goroutines
Close() error
}
ExtendedCache extends Cache with management capabilities
func NewDiskCacheWithConfig ¶
func NewDiskCacheWithConfig(dir string, config *CacheConfig) (ExtendedCache, error)
NewDiskCacheWithConfig returns a disk-backed cache with custom configuration
func NewMemoryCacheWithConfig ¶
func NewMemoryCacheWithConfig(config *CacheConfig) ExtendedCache
NewMemoryCacheWithConfig returns an ephemeral cache with custom configuration
func NewVFSCacheWithConfig ¶
func NewVFSCacheWithConfig(fs vfs.VFS, config *CacheConfig) ExtendedCache
NewVFSCacheWithConfig returns a cache backend with custom configuration
type Handler ¶
type Handler struct {
// proxy) rather than private to one (a browser-style cache).
//
// It defaults to false, which is the *private* cache profile: responses
// marked "Cache-Control: private" and responses to requests carrying an
// Authorization header are storable. Deploying a shared cache without
// setting this serves one user's response to another. Prefer
// NewSharedHandler, which cannot be forgotten.
Shared bool
// contains filtered or unexported fields
}
func NewHandler ¶
NewHandler returns a private cache handler with default options (package-level logger). Use NewSharedHandler for a cache that is shared between users, such as a reverse proxy.
func NewHandlerWithOptions ¶
func NewHandlerWithOptions(cache Cache, upstream http.Handler, opts *HandlerOptions) *Handler
NewHandlerWithOptions returns a cache handler with the given options. If opts.Logger is set, it is used for handler logging; otherwise the package-level logger is used.
func NewSharedHandler ¶ added in v2.2.0
NewSharedHandler returns a cache handler configured as a shared cache: it refuses to store "Cache-Control: private" responses and responses to authorized requests unless they are explicitly marked public or carry s-maxage, and it strips headers listed in "private" before storing.
This is the constructor to use for a reverse proxy. NewHandler leaves Shared false, which is correct for a per-user cache and unsafe for a shared one.
func (*Handler) SetMetrics ¶
func (h *Handler) SetMetrics(m *CacheMetrics)
SetMetrics sets the metrics instance for the handler
type HandlerOptions ¶
type HandlerOptions struct {
Logger *logger.Logger
// StaleMarkerTTL is how long the handler remembers an invalidation for a
// Cache that does not implement StaleAt itself.
//
// It must be at least as long as that Cache retains entries: the marker is
// the only record that entries older than it are pre-mutation, so expiring
// it first republishes them as fresh. Only the implementation knows its
// own retention, which is why this is a knob rather than a constant.
//
// Zero means DefaultCacheTTL. A Cache that implements StaleAt keeps its
// own record and ignores this.
StaleMarkerTTL time.Duration
}
HandlerOptions holds optional configuration for NewHandlerWithOptions. Logger injected here is used by the handler for all debug/error logging; if nil, the package-level logger (see SetLogger) is used.
type Key ¶
type Key struct {
// contains filtered or unexported fields
}
Key represents a unique identifier for a resource in the cache
func NewRequestKey ¶
NewRequestKey generates a Key for a request.
The key is derived from the effective request URI only. A request header must never be able to choose which cache entry a response is stored under: letting the *request's* Content-Location pick the key allowed a client to park its own response under another URL's key ("GET /attacker-page" with "Content-Location: /admin"), poisoning a shared cache for every other user.
RFC 7234 does use Content-Location, but the *response's* — and only to invalidate entries, never to select a storage key. See invalidationKeys.
type Resource ¶
type Resource struct {
ReadSeekCloser
RequestTime, ResponseTime time.Time
// contains filtered or unexported fields
}
func NewResource ¶
func NewResource(statusCode int, body ReadSeekCloser, hdrs http.Header) *Resource
func (*Resource) HasExplicitExpiration ¶
func (*Resource) HasValidators ¶
func (*Resource) HeuristicFreshness ¶
func (*Resource) IsNonErrorStatus ¶
func (*Resource) LastModified ¶
func (*Resource) MustValidate ¶
func (*Resource) RemovePrivateHeaders ¶
func (r *Resource) RemovePrivateHeaders()
func (*Resource) SetStoredAt ¶ added in v2.2.0
ReceivedAfter reports whether this response reached the cache after d.
It reads Proxy-Date, which the handler stamps from the LOCAL clock the moment the upstream response arrives, and only falls back to the origin's Date for a response stored without one.
Deciding this from Date alone was wrong in both directions. A response that carries no Date at all -- which a direct http.Handler upstream may well omit -- never counted as superseding anything, so an invalidated key stayed stale on every retrieval and was refetched until the marker was swept. An origin whose clock trails the cache's did the same. Proxy-Date is always present and always this machine's clock.
Receive time, not store time: an older store still in flight when a mutation lands carries a Proxy-Date from BEFORE the invalidation, so the marker still wins and the pre-mutation body is not republished as fresh.
Both stamps are HTTP dates, so this is second-granular: a replacement that arrives in the same second as the invalidation does not count as superseding it and is refetched once more. That is the safe direction to round in. SetStoredAt records when this cache wrote the entry.
func (*Resource) StoredAfter ¶ added in v2.2.0
StoredAfter reports whether this cache's copy is newer than d.
It prefers the cache's OWN store time to the response's dates, because Date and Proxy-Date are HTTP dates: one-second granularity, formatted with http.TimeFormat. An invalidation marker is a full-precision time.Time, so a response stored or revalidated in the same second as the invalidation is never "after" it -- and being judged against a marker it can never clear, the entry was re-marked stale and revalidated upstream on EVERY request until the marker was swept. The store time is also ours rather than the origin's, so a trailing origin clock cannot produce the same deadlock.
Falls back to the header dates for a resource that did not come from this cache, which is the only thing available for one.