cache

package
v0.1.16 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ResponseCache

type ResponseCache struct {
	// contains filtered or unexported fields
}

ResponseCache is a thread-safe in-memory response cache keyed by (tenantID, requestURI) with a fixed TTL. Items are served on exact-match GET requests and evicted at TTL.

func New

func New(ttl time.Duration) *ResponseCache

New returns a ResponseCache with the given TTL and starts a background goroutine that purges expired items every 30 seconds.

func (*ResponseCache) Invalidate

func (rc *ResponseCache) Invalidate(tenantID string)

Invalidate removes all cached entries for tenantID and bumps its epoch so any in-flight refresh/store started before this point is discarded on completion (see the epochs field). Call this when a schema_updated pg_notify arrives for that tenant.

func (*ResponseCache) Middleware

func (rc *ResponseCache) Middleware(next http.Handler) http.Handler

Middleware returns an http.Handler that sits after authentication/RBAC in the chain and short-circuits identical GET requests with cached bodies.

Rules:

  • Only GET requests are cached.
  • Requests with Cache-Control: no-cache bypass the cache entirely.
  • Requests with If-None-Match bypass the cache (let ETag/304 logic handle them).
  • Only HTTP 200 responses are stored.
  • At most maxPerTenant (1000) entries per tenant; new entries are dropped when full.

func (*ResponseCache) SetBypassMatcher

func (rc *ResponseCache) SetBypassMatcher(fn func(path string) bool)

SetBypassMatcher declares which paths the cache must never buffer or store (LOOSE-ENDS-SWEEP-S1) — user-declared static mounts. A frontend's assets are already cached by the browser (immutable hashed filenames) and range-served by http.ServeContent; putting them through captureWriter would buffer every JS chunk and image into RAM, per tenant, for nothing. Same reasoning as the built-in /api/files/ and /admin/ bypasses, but a mount is per-app (and a root mount is not expressible as a prefix), so it is a predicate set at boot. nil — the default — leaves the hot path byte-identical.

func (*ResponseCache) SetJWTSecret

func (rc *ResponseCache) SetJWTSecret(s string)

SetJWTSecret scopes the cache's claims-cache lookups to the app's JWT secret (see the jwtSecret field). Called once at boot, before serving.

func (*ResponseCache) SetRoleCacheGate

func (rc *ResponseCache) SetRoleCacheGate(fn func(role string) bool)

SetRoleCacheGate installs a predicate that decides, per role, whether the response cache may store and serve that role's responses. Roles that fail the gate bypass the cache entirely so their RBAC conditions run on every request. Atomic (MT-STRUCT-S4): safe to re-call on a hot-swap while requests read it.

Jump to

Keyboard shortcuts

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