contextutil

package
v1.8.2 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package contextutil provides context lifecycle helpers shared by transports and middleware.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CarrierLookup added in v1.8.0

func CarrierLookup(c Carrier, key any) (any, bool)

CarrierLookup answers the carrier-discovery key on behalf of an implementation: a Carrier's Value method delegates to it before its own lookups, so the package-level helpers can find the carrier through any number of derived contexts.

func EffectiveError

func EffectiveError(ctx context.Context) error

EffectiveError reports a context cancellation even at the narrow deadline boundary where the wall clock has reached Deadline but the context timer goroutine has not yet published Err. This matters after a socket operation: the kernel deadline can return first, and treating that I/O timeout as upstream evidence would leak a request-local failure into shared state.

func PinnedValue

func PinnedValue(ctx context.Context, key any) (any, bool)

PinnedValue returns the exact value stored in the carrier's request-lifetime slot for key. Unlike ctx.Value, it never falls through to a value provider or parent context.

func TryPinValue

func TryPinValue(ctx context.Context, key, value any) bool

TryPinValue stores one request-lifetime control value directly on the carrier reachable through ctx. The pin survives pooled metadata reuse without allocating a context.WithValue node. It is deliberately not exposed through Context.Value: callers must use PinnedValue, keeping the ordinary context value chain immutable. Re-pinning a key that is already pinned fails, as does pinning into a full table.

func TrySetValueProvider

func TrySetValueProvider(ctx context.Context, provider ValueProvider) bool

TrySetValueProvider installs provider on the carrier reachable through ctx. It returns false for ordinary contexts or when a provider was already installed.

func TryUpdatePinnedValueLocked

func TryUpdatePinnedValueLocked[T comparable](
	ctx context.Context,
	key any,
	old T,
	update func() T,
) (T, bool)

TryUpdatePinnedValueLocked computes and installs a replacement while holding the carrier's request-lifetime lock. It is intended for transitions whose initialization must complete before a concurrent request owner can close and recycle adjacent pooled state.

update must be bounded and must not call the pin mutation APIs recursively on ctx (or a context derived from it): the pin lock is deliberately non-reentrant. Cancellation methods use separate locks, so update may safely inspect Done, Err or context.AfterFunc. The Locked suffix exposes the callback contract at each call site.

func UpdatePinnedTransitionLocked added in v1.8.0

func UpdatePinnedTransitionLocked(ctx context.Context, key any, t PinTransition) (any, bool)

UpdatePinnedTransitionLocked runs t against the carrier reachable through ctx. It exists for hot transitions: the closure-based TryUpdatePinnedValueLocked allocates its adapter and captures on every call, which a live profile priced at two objects per materialized request.

Types

type Carrier added in v1.8.0

type Carrier interface {
	context.Context

	TryPin(key, value any) bool
	Pinned(key any) (any, bool)
	UpdatePinLocked(key any, update func(current any) (next any, ok bool)) (any, bool)

	// UpdatePinTransitionLocked is UpdatePinLocked with the transition
	// carried as an interface value instead of a closure. A closure
	// forces its captures to the heap at every call site; a transition
	// implemented on state the caller already owns rides its existing
	// pointer and costs nothing. Same lock, same reentrancy and non-nil
	// rules.
	UpdatePinTransitionLocked(key any, t PinTransition) (any, bool)
	TrySetProvider(provider ValueProvider) bool
}

Carrier is the request-lifetime anchor a context exposes: the pin table and the value provider that request-scoped machinery (response metadata, recursion-work accounting, the resolution-attempt guard, caches' memo state) rides on without deriving value contexts.

Two implementations exist by design: *LazyDeadline, the ordinary request context, and the server's job carrier, which serves the allocation-free fast path and is recycled between requests. Everything that pins or reads request-lifetime values goes through the package-level helpers (TryPinValue, PinnedValue, TryUpdatePinnedValueLocked, TrySetValueProvider), which resolve the carrier from the context and work identically on either implementation.

Contract for implementers:

  • TryPin stores value under key exactly once; re-pinning a key that is already pinned fails, as does pinning into a full table. key and value are never nil interfaces.
  • Pinned returns the exact stored value. It must be safe under the implementation's declared concurrency (LazyDeadline: lock-free readers; the job carrier: single-owner with a cheap lock).
  • UpdatePinLocked calls update with the current value while holding the carrier's pin lock and stores the returned value when ok. update must be bounded and must not call the pin APIs recursively on the same carrier; the lock is deliberately non-reentrant. The stored value must not be a nil interface. When the slot is missing it returns (nil, false); when update declines it returns (current, false).
  • TrySetProvider installs the value provider once; a second install fails.

func CarrierFrom added in v1.8.0

func CarrierFrom(ctx context.Context) Carrier

CarrierFrom returns the carrier reachable through ctx, or nil.

type LazyDeadline

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

func WithLazyDeadline

func WithLazyDeadline(parent context.Context, deadline time.Time) *LazyDeadline

WithLazyDeadline returns a LazyDeadline with the earlier of deadline and the parent's deadline. Call Cancel when the request finishes.

func WithLazyTimeout

func WithLazyTimeout(parent context.Context, timeout time.Duration) *LazyDeadline

WithLazyTimeout returns a LazyDeadline whose deadline is no later than the parent's. Call Cancel when the request finishes.

func (*LazyDeadline) Cancel

func (c *LazyDeadline) Cancel()

Cancel releases an armed timer/parent registration, or records a terminal cause without arming one when the request completed on the fast path.

func (*LazyDeadline) Deadline

func (c *LazyDeadline) Deadline() (time.Time, bool)

Deadline implements context.Context.

func (*LazyDeadline) Done

func (c *LazyDeadline) Done() <-chan struct{}

Done implements context.Context. Its first live call materializes the standard-library deadline context so timer and parent cancellation semantics remain identical on paths that actually block.

func (*LazyDeadline) Err

func (c *LazyDeadline) Err() error

Err implements context.Context. A parent cancellation or elapsed deadline materializes the standard context to pin the first terminal cause.

func (*LazyDeadline) Pinned added in v1.8.0

func (c *LazyDeadline) Pinned(key any) (any, bool)

Pinned implements Carrier: it returns the exact value stored in the request-lifetime slot for key, lock-free.

func (*LazyDeadline) TryPin added in v1.8.0

func (c *LazyDeadline) TryPin(key, value any) bool

TryPin implements Carrier. Re-pinning a key that is already pinned fails, as does pinning into a full table.

func (*LazyDeadline) TrySetProvider added in v1.8.0

func (c *LazyDeadline) TrySetProvider(provider ValueProvider) bool

TrySetProvider implements Carrier. A second install fails.

func (*LazyDeadline) UpdatePinLocked added in v1.8.0

func (c *LazyDeadline) UpdatePinLocked(
	key any,
	update func(current any) (next any, ok bool),
) (any, bool)

UpdatePinLocked implements Carrier: update runs with the current slot value while pinMu is held, and its return value is stored when ok. See the Carrier contract for the reentrancy and non-nil rules.

func (*LazyDeadline) UpdatePinTransitionLocked added in v1.8.0

func (c *LazyDeadline) UpdatePinTransitionLocked(key any, t PinTransition) (any, bool)

UpdatePinTransitionLocked implements Carrier; see the interface contract. The body mirrors UpdatePinLocked with the transition on an interface instead of a closure.

func (*LazyDeadline) Value

func (c *LazyDeadline) Value(key any) any

Value implements context.Context. Once materialized, values are deliberately routed through the standard child context. Besides preserving values, this lets context.WithCancel/WithDeadline recognize its private parent fast path instead of spawning a propagation goroutine.

type PinTransition added in v1.8.0

type PinTransition interface {
	NextLocked(current any) (next any, ok bool)
}

PinTransition computes a pinned value's replacement while the pin lock is held. NextLocked follows UpdatePinLocked's callback contract: it must be bounded, must not touch the pin APIs reentrantly, and a false return leaves the current value in place.

type ValueProvider

type ValueProvider interface {
	ContextValue(key any) (value any, ok bool)
}

ValueProvider supplies request-local context values without adding another context.WithValue wrapper to a LazyDeadline. Providers are installed before the context is published to middleware and must be safe for concurrent use.

Jump to

Keyboard shortcuts

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