decorator

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Oct 10, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package decorator provides one generic implementation of the cross-cutting decorator stack (timeout, circuit breaker, metrics, tracing, logging, recovery) shared by every tier whose unit of work has the shape Execute(ctx, In) (Out, error) — pipelines and workflows today. Each tier keeps its own fluent builder (and therefore its own wrap order (ARCHITECTURE.md#decorator-order) and its tier-specific labels/recovery behavior); this package holds the decorator implementations those builders compose, so a decorator fix is made once instead of once per tier.

The constructors take a caller-supplied inner Executor and return a decorated Executor — the builder chooses the order, this package does not hardcode one. Every returned decorator also implements Unwrapper so a test can reach the underlying handler through the stack.

Index

Constants

This section is empty.

Variables

View Source
var DefaultBuckets = []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}

DefaultBuckets are the default histogram bucket boundaries (in seconds) for execution-duration metrics.

Functions

This section is empty.

Types

type Executor

type Executor[In any, Out any] interface {
	// Execute runs the wrapped unit of work for input, returning its result or an error.
	Execute(ctx context.Context, input In) (Out, error)
}

Executor is the single-method shape the decorators wrap. interfaces.Pipeline and interfaces.Workflow have the identical method set, so one decorator set serves both tiers (and any future Execute(ctx, In) (Out, error) tier).

interface-composition exemption — decoration mechanism primitive: the generic Execute(ctx, In) (Out, error) shape the decorators wrap, not an id-CRUD data-access surface, so it embeds no foundation generic.

func CircuitBreaker added in v0.3.2

func CircuitBreaker[In, Out any](inner Executor[In, Out], cb interfaces.CircuitBreaker, onOpen func(error) error) Executor[In, Out]

CircuitBreaker returns inner run through cb. When cb rejects the call without running inner (an open breaker), Execute returns onOpen(err) so the tier can code the rejection; an error from inner itself passes through unchanged.

func Logging

func Logging[In, Out any](
	inner Executor[In, Out],
	logger interfaces.Logger,
	tier, name string,
) Executor[In, Out]

Logging returns inner wrapped with entry/failure logging at Debug level (the error is logged once at the transport layer in staging/prod). tier is both the log-message prefix (tier+".Execute") and the field key; name is the field value.

func Metrics

func Metrics[In, Out any](
	inner Executor[In, Out],
	tier, name string,
	m interfaces.Metrics,
	buckets []float64,
) Executor[In, Out]

Metrics returns inner wrapped with execution-count, error-count, and duration-histogram metrics. tier prefixes the metric names (tier+"_executions_total" etc.) and is the label key (e.g. "pipeline"); name is the label value — the per-instance pipeline/workflow name — so each instance is its own time series (passing tier as the value would collapse every instance into one mislabeled series).

func Recovery

func Recovery[In, Out any](
	inner Executor[In, Out],
	logger interfaces.Logger,
	tier, name string,
	onPanic func(name string, r any) error,
) Executor[In, Out]

Recovery returns inner wrapped with panic recovery (always outermost in the tier builders' order, ARCHITECTURE.md#decorator-order). A recovered panic is logged as tier+" panic recovered" and the returned error is produced by onPanic, so each tier keeps its own recovery-error contract (a coded error, a plain wrap, …). A nil onPanic falls back to a generic wrapped error, so the recovery path never itself panics on a missing contract.

func Timeout

func Timeout[In, Out any](inner Executor[In, Out], d time.Duration) Executor[In, Out]

Timeout returns inner wrapped with a per-execution context deadline. A slow execution is cancelled via context when the deadline elapses.

func Tracing

func Tracing[In, Out any](
	inner Executor[In, Out],
	tracer interfaces.Tracer,
	tier, name string,
) Executor[In, Out]

Tracing returns inner wrapped with a trace span per execution, named name+".Execute" and carrying the tier+".name" attribute, so the request cascade is visible in Tempo.

type Unwrapper

type Unwrapper[In any, Out any] interface {
	// Unwrap returns the inner Executor this decorator wraps.
	Unwrap() Executor[In, Out]
}

Unwrapper exposes the inner Executor a decorator wraps, so a test can reach the underlying handler through the decorator stack (the Unwrap seam). Every decorator constructed here implements it.

interface-composition exemption — decoration mechanism primitive: a single Unwrap() → Executor introspection port, not an id-CRUD data-access surface, so it embeds no foundation generic.

Jump to

Keyboard shortcuts

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