Documentation
¶
Index ¶
- type ResponseCache
- func (rc *ResponseCache) Invalidate(tenantID string)
- func (rc *ResponseCache) Middleware(next http.Handler) http.Handler
- func (rc *ResponseCache) SetBypassMatcher(fn func(path string) bool)
- func (rc *ResponseCache) SetJWTSecret(s string)
- func (rc *ResponseCache) SetRoleCacheGate(fn func(role string) bool)
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.