Documentation
¶
Index ¶
- Variables
- func DefaultTenantIDPattern() *regexp.Regexp
- func FanOutRetentionCleanup(ctx context.Context, log logger.Logger, tenants []string, ...) error
- func ForEachTenant(ctx context.Context, tenants []string, ...) error
- func GetTenant(ctx context.Context) (string, bool)
- func SetTenant(ctx context.Context, tenantID string) context.Context
- func TenantID(ctx context.Context) (string, error)
- func ValidateTenantID(id string) error
- type CompositeResolver
- type HeaderResolver
- type PathResolver
- type RetentionDelete
- type SubdomainResolver
- type TenantResolver
- type ValidatingResolver
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidTenantID = errors.New("multitenant: tenant id does not match the default grammar")
ErrInvalidTenantID reports a tenant identifier that does not match DefaultTenantIDPattern.
var ErrNoTenant = errors.New("multitenant: no tenant in context")
ErrNoTenant reports a context that carries no tenant. It is the error form of GetTenant's ok result, so every lane answers "no tenant" the same way.
var ErrTenantResolutionFailed = errors.New("tenant resolution failed")
ErrTenantResolutionFailed is returned when a resolver cannot determine the tenant identifier.
var ErrUntrustedForwardedHost = errors.New("multitenant: X-Forwarded-Host from an untrusted peer")
ErrUntrustedForwardedHost is returned by a SubdomainResolver with TrustProxies set when a peer it does not trust sends X-Forwarded-Host. CompositeResolver stops on it instead of trying the next sub-resolver.
Functions ¶
func DefaultTenantIDPattern ¶ added in v0.61.0
DefaultTenantIDPattern returns the framework's tenant identifier grammar.
func FanOutRetentionCleanup ¶ added in v0.42.0
func FanOutRetentionCleanup( ctx context.Context, log logger.Logger, tenants []string, getDB func(context.Context) (dbtypes.Interface, error), retention time.Duration, name string, del RetentionDelete, ) error
FanOutRetentionCleanup runs a retention delete once per tenant, resolving each tenant's database via getDB with that tenant injected into the context (SetTenant). Per-tenant errors AND panics are collected with errors.Join so one unhealthy tenant cannot block the others. Single-tenant callers pass tenants=[""] (SetTenant("") is a no-op). name labels the job in log and error messages (e.g. "outbox", "inbox").
This is shared by the outbox and inbox cleanup jobs, whose Execute bodies are otherwise identical — only the store delete and the label differ.
func ForEachTenant ¶ added in v0.72.0
func ForEachTenant(ctx context.Context, tenants []string, fn func(ctx context.Context, tenantID string) error) error
ForEachTenant runs fn once per tenant, in the given order, each inside that tenant's own lease scope (ADR-032): the tenant's context carries the tenant (SetTenant; "" runs fn once with no tenant) and a fresh scope that shadows any enclosing request, message or job scope, drained when fn returns or panics. A tenant-sweeping job then holds about one tenant's leased handles at a time instead of every tenant's until the job returns.
ctx is checked before each tenant: once it is done no further tenant starts and ctx.Err() joins the result. Errors from fn are joined unwrapped (fn receives the tenant ID and owns its text) and the sweep continues. A panic in fn is not recovered; it propagates after that tenant's scope has drained. A nil or empty list returns nil.
Every borrow inside fn must use fn's ctx or a context derived from it: a borrow on the outer context lands in the enclosing scope and is not bounded. A handle, database.Session or transaction obtained inside fn must not be used after fn returns. Releasing a lease does not close a cached handle, so the bound matters only when a sweep covers more tenants than the manager's max size. The caller supplies the list: Config.PerTenantJobKeys() for static tenants, or its own list for dynamic sources.
func TenantID ¶ added in v0.61.0
TenantID is GetTenant in error form: the tenant identifier, or ErrNoTenant.
func ValidateTenantID ¶ added in v0.61.0
ValidateTenantID checks an identifier against DefaultTenantIDPattern.
SECURITY: the identifier is caller-written (an HTTP header, a message stamp), so the error carries its byte length only — never the value itself.
Types ¶
type CompositeResolver ¶
type CompositeResolver struct {
Resolvers []TenantResolver
TenantRegex *regexp.Regexp // Optional validation pattern
}
CompositeResolver tries multiple resolvers until one succeeds. ErrUntrustedForwardedHost is terminal: it is returned at once and no later resolver is tried.
func (*CompositeResolver) ResolveTenant ¶
ResolveTenant implements TenantResolver.
type HeaderResolver ¶
type HeaderResolver struct {
HeaderName string
}
HeaderResolver extracts the tenant identifier from a configured request header.
func (*HeaderResolver) ResolveTenant ¶
ResolveTenant implements TenantResolver.
type PathResolver ¶ added in v0.34.0
PathResolver extracts the tenant identifier from a path segment.
Segment is 1-indexed (segment 1 is the first non-empty path part after the leading slash). When Prefix is non-empty, the resolver only attempts extraction for requests whose path equals Prefix exactly or starts with "Prefix/" — non-matching paths return ErrTenantResolutionFailed so the composite chain (if any) can fall through to other resolvers.
func (*PathResolver) ResolveTenant ¶ added in v0.34.0
ResolveTenant implements TenantResolver.
type RetentionDelete ¶ added in v0.42.0
type RetentionDelete func(ctx context.Context, db dbtypes.Interface, cutoff time.Time) (int64, error)
RetentionDelete removes rows older than cutoff from the resolved tenant database. It is the per-vendor delete a retention-cleanup job runs (e.g. the outbox's DeletePublished or the inbox's DeleteProcessed) and matches those store methods' signatures directly.
type SubdomainResolver ¶
type SubdomainResolver struct {
RootDomain string
TrustProxies bool
// TrustedProxies adds peer ranges trusted to send X-Forwarded-Host, on top of
// loopback, link-local, private and unix-socket peers.
TrustedProxies []*net.IPNet
}
SubdomainResolver extracts the tenant identifier from the request host.
func (*SubdomainResolver) ResolveTenant ¶
ResolveTenant implements TenantResolver.
type TenantResolver ¶
type TenantResolver interface {
ResolveTenant(ctx context.Context, req *http.Request) (string, error)
}
TenantResolver resolves the tenant identifier from an incoming request.
type ValidatingResolver ¶
type ValidatingResolver struct {
Resolver TenantResolver
TenantRegex *regexp.Regexp
}
ValidatingResolver wraps any resolver with tenant ID validation.
func (*ValidatingResolver) ResolveTenant ¶
ResolveTenant implements TenantResolver with validation.