Documentation
¶
Index ¶
- func IsDependencyError(err error) bool
- func IsRetryable(err error) bool
- func IsUserError(err error) bool
- func NewDependencyError(cause error) error
- func NewRetryableDependencyError(cause error) error
- func NewRetryableError(cause error) error
- func NewUserError(cause error) error
- type Classifier
- type ErrorProcessor
- type Verdict
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsDependencyError ¶
IsDependencyError reports whether err is or wraps an infra error marked as originating in a downstream dependency, i.e. an error produced by NewDependencyError or NewRetryableDependencyError. Inspects only the framework types in the chain.
func IsRetryable ¶
IsRetryable reports whether err is or wraps an infra error marked retryable, i.e. an error produced by NewRetryableError or NewRetryableDependencyError. Inspects only the framework types in the chain.
func IsUserError ¶
IsUserError reports whether err is or wraps a user error, i.e. an error produced by NewUserError. Inspects only the framework types in the chain.
func NewDependencyError ¶
NewDependencyError creates a non-retryable dependency infra error wrapping the given cause. A dependency error is an error that is caused by a downstream dependency outside the control of the current system, for example an external build system being down.
func NewRetryableDependencyError ¶
NewRetryableDependencyError creates a retryable dependency infra error wrapping the given cause. A retryable dependency error is an error that is caused by a downstream dependency outside the control of the current system, for example an external build system being down.
func NewRetryableError ¶
NewRetryableError creates a retryable infra error wrapping the given cause.
func NewUserError ¶
NewUserError creates a user error wrapping the given cause. A user error is an error that is caused by the user's action or input, for example an invalid input or a merge conflict. User errors are never retryable — only infrastructure errors can be retryable.
Types ¶
type Classifier ¶
Classifier inspects a single error node (not the whole chain) and returns a Verdict. Implementations should return Unknown for nodes they do not recognize so the chain walker can continue down the unwrap chain.
Classifiers must not call errors.As / errors.Is themselves, which would walk the chain and could shadow a classification carried by an outer node (such as a controller's explicit NewUserError wrap). The classifier-based ErrorProcessor (see NewClassifierProcessor) owns the walk.
Classifiers are typically stateless; the canonical convention is to expose a package-level singleton value (e.g. mysqlerrs.Classifier) rather than a constructor.
type ErrorProcessor ¶
ErrorProcessor transforms an error returned by a controller into the error the surrounding transport will react to. It runs exactly once per failing delivery — typically called by the consumer immediately after a controller returns — and the result is what IsRetryable / IsUserError / IsDependencyError will subsequently inspect.
Two implementations ship in this package:
NewClassifierProcessor runs a per-node classifier walk. This preserves controller-attached framework wraps (NewUserError, NewDependencyError, ...) verbatim and only invokes the supplied classifiers when the chain carries no existing framework type. Use it for primary pipeline consumers where controller-driven classification is the source of truth.
AlwaysRetryableProcessor unconditionally wraps every non-nil error with NewRetryableError, overriding any inner framework wrap. Use it for narrowly-scoped consumers — typically DLQ reconciliation — that must redeliver on any failure because there is no further dead-letter destination.
Separating "decide how an error is interpreted" from "decide what to do with the interpreted error" lets the same consumer implementation host transports with very different retry policies without leaking the policy into each Controller.
var AlwaysRetryableProcessor ErrorProcessor = alwaysRetryableProcessor{}
AlwaysRetryableProcessor classifies every non-nil error as InfraRetryable by wrapping it with NewRetryableError. The wrap is unconditional: an inner *userError or non-retryable *infraError is overridden because errors.As (used by IsRetryable) matches the outermost *infraError first, and that outer wrap is always retryable=true.
Side-effect: an inner *infraError carrying dependency=true is masked. The outer wrap is constructed with dependency=false, so IsDependencyError on the result returns false even though the original chain originated in a dependency. This is acceptable for the intended DLQ-reconciliation use case where only IsRetryable drives transport behavior; if dependency provenance ever needs to survive this processor it must be added here explicitly.
Pair this only with consumers whose controllers should retry on any returned error. On a primary pipeline consumer this would loop forever on genuine user errors and prevent them from reaching the DLQ.
func NewClassifierProcessor ¶
func NewClassifierProcessor(classifiers ...Classifier) ErrorProcessor
NewClassifierProcessor returns an ErrorProcessor that runs the supplied classifiers over the chain of any non-nil error.
Semantics of Process on the returned processor:
- nil in, nil out.
- If err's chain already carries a framework classification (*userError or *infraError anywhere in the chain), returns err unchanged — the chain is already interpretable by IsUserError / IsRetryable / IsDependencyError.
- Otherwise, walks the chain from outermost to innermost, asking each classifier per node. The FIRST non-Unknown verdict wins; the outermost such node determines the wrap. err is wrapped with the framework constructor matching that verdict (User -> NewUserError, InfraRetryable -> NewRetryableError, etc.) and the wrapped error is returned.
- Verdict Infra means "non-retryable infra" — which is already the default behavior for an unwrapped chain, so no wrap is added.
- If no classifier recognises anything, err is returned unchanged.
Implementation: two passes over the chain. Pass 1 is a cheap type check looking for an existing framework wrap and short-circuits if one is found — no classifier is invoked. Pass 2 runs the configured classifiers per node. Walking the chain is cheap relative to a classifier call, so this avoids running classifiers whenever the chain is already classified deeper down.
Passing no classifiers is valid — the processor will still honour any framework wrap already in the chain and otherwise return err unchanged.
NOTE: this central classifier model cannot disambiguate errors of the same underlying type produced by different extensions (e.g. a net.OpError from a mysql connection vs the same type from an HTTP caller would both match the mysql classifier here). Resolving that requires per-extension provenance tagging; intentionally deferred.
type Verdict ¶
type Verdict int
Verdict is the classification of a single error node, returned by a Classifier. Unknown means the node carries no signal and the chain walker should keep looking; every other value names a terminal classification.
const ( // Unknown means this node carries no classification. The chain walker // will move on to the next node in the unwrap chain. Unknown Verdict = iota // User means the error is caused by the user's input or action (e.g. a // merge conflict or invalid request) and must not be retried. User // Infra means a non-retryable infrastructure failure: something below the // caller broke in a way that retrying will not fix (e.g. a schema or // programmer bug). This is the implicit verdict for an unclassified chain, // so Classify does not add a wrap for it. Infra // InfraRetryable means a transient infrastructure failure that is // expected to succeed on retry (e.g. a deadlock, lock-wait timeout, or // dropped connection). InfraRetryable // InfraDependency means a non-retryable failure originating in a // downstream dependency outside the caller's control (e.g. an external // service rejecting the request). InfraDependency // InfraDependencyRetryable means a transient failure originating in a // downstream dependency (e.g. an external service is briefly unavailable) // that is expected to succeed on retry. InfraDependencyRetryable )
Directories
¶
| Path | Synopsis |
|---|---|
|
Package generic provides an errs.Classifier for errors that are not tied to any particular backend.
|
Package generic provides an errs.Classifier for errors that are not tied to any particular backend. |
|
Package mysql provides an errs.Classifier for errors originating from the go-sql-driver/mysql driver and the standard database/sql + net packages commonly seen when talking to a MySQL backend.
|
Package mysql provides an errs.Classifier for errors originating from the go-sql-driver/mysql driver and the standard database/sql + net packages commonly seen when talking to a MySQL backend. |