org

package
v1.49.60 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package org resolves — and memoizes — the organization a request acts on behalf of. It is the ONE org-resolution path in commerce: the IAM/gateway identity middleware and the verified-service-token branch both land here.

WHY THE CACHE EXISTS (money-critical, incident 2026-07-04):

Resolution used to call GetOrCreate("Name=", name) on EVERY request, on the caller's cancelable request context. Under concurrent load (many orgs, e2e first-touch of NEW orgs, and the auto-recharge cron all sharing commerce's single writer) that read-then-maybe-create serialized behind the writer; when the wait exceeded the caller's deadline the query returned "context canceled", auth fell through to the legacy per-org-token path, tried to Peek a service token as a JWT, and 401'd — so cloud-api's balance gate fail-secured to 402 and real customers could not run paid inference.

  • CACHE: an LRU keyed by org name with a short TTL. A hit does ZERO datastore work, so ORG RESOLUTION touches no SQL in the steady state. That is a claim about this package only — the IAM middleware still fires its trial on-ramp per authenticated request, which does query; what bounds the store there is that path's own concurrency cap, not this cache.
  • SINGLEFLIGHT: concurrent misses for one name collapse into ONE GetOrCreate, so a burst of first requests for a brand-new org performs exactly one create, not N contending writes.
  • DETACHED + BOUNDED: resolution runs on a fresh context.Background() with its OWN timeout, so a slow resolve fast-fails inside commerce instead of being canceled mid-create by an upstream deadline.

WHY THE HOT PATH MUST NOT TOUCH THE STORE (2026-07-18 SEV1, heap profile):

Resolve allocates the Organization BEFORE it issues its query. A request blocked in that query therefore keeps a live 5,256-byte struct reachable from its goroutine stack for as long as it waits. When the connection pool starved (unclosed single-row iterators, fixed in 24ff20a68) thousands of requests blocked here for their full 10s deadline at once, and the heap filled with tens of thousands of simultaneously-live Organizations — 40% of the process heap in the v1.801.88 profile. Serving the steady state from memory removes the blocking I/O from the hot path, so the pile-up cannot form.

WHY RESOLVE RETURNS A COPY:

The cached Organization is a 5,256-byte struct that callers MUTATE per request — notably o.Live, the live/test switch deciding whether a charge hits a sandbox or a real processor. Handing the same pointer to concurrent requests would let a test-mode request flip Live for a live one: a data race and a money bug. The cached entry is therefore IMMUTABLE and every caller gets its own copy bound to that request's datastore. Callers mutate freely; the cache can never be corrupted, and two requests for the same org can never observe each other's writes.

Index

Constants

This section is empty.

Variables

View Source
var ErrResolveFailed = errors.New("org: could not resolve organization")

ErrResolveFailed wraps any failure to resolve/provision an org for an already-authenticated caller. Treat it as retryable (HTTP 503), never as a bad credential — the credential was verified; only the backing store hiccuped.

Functions

func Invalidate added in v1.49.3

func Invalidate(name string)

Invalidate drops a name so the next Resolve re-reads it. Call after mutating an org's identity fields (Name/Enabled/Live) so a change is not masked by the TTL. Safe to call for an absent name.

func Resolve

func Resolve(ctx context.Context, name string) (*organization.Organization, error)

Resolve returns the organization named name, creating it if it does not yet exist. The returned value is owned by the caller and safe to mutate.

Steady state (name cached, unexpired) does NO datastore work. A miss resolves under singleflight on a detached, bounded context, so concurrent misses for the same name share one GetOrCreate and a slow store fast-fails with ErrResolveFailed instead of blocking on the caller's deadline.

Types

This section is empty.

Jump to

Keyboard shortcuts

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