Skip to content

refactor(errs): introduce per-backend Classifier framework#183

Merged
behinddwalls merged 2 commits into
mainfrom
errors
Jun 3, 2026
Merged

refactor(errs): introduce per-backend Classifier framework#183
behinddwalls merged 2 commits into
mainfrom
errors

Conversation

@sbalabanov
Copy link
Copy Markdown
Contributor

@sbalabanov sbalabanov commented Jun 3, 2026

Summary

Implements an error classification framework in core/errs: per-backend Classifier implementations recognise raw driver/library errors and the consumer runs a single errs.Classify(err, classifiers...) pass after each delivery. Downstream IsRetryable / IsUserError / IsDependencyError become plain type checks; an explicit framework wrap from a controller always wins over any classifier.

  • Adds errs.Classifier interface, Verdict enum, and errs.Classify (two-pass: framework-wrap short-circuit, then classifier walk).
  • New core/errs/genericcontext.Canceled → retryable infra.
  • New core/errs/mysql — server error numbers, driver.ErrBadConn, sql.ErrConnDone/TxDone, net.Error. Never returns User; controllers wrap constraint violations with NewUserError explicitly.
  • Orchestrator's consumer.New wires both classifiers.
  • core/errs/README.md documents the framework, adding classifiers, and controller overrides.

Test plan

  • CI green

🤖 Generated with Claude Code

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Jun 3, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ behinddwalls
❌ sbalabanov-zz
You have signed the CLA already but the status is still pending? Let us recheck it.

Replaces the implicit context.Canceled handling in IsRetryable with an
explicit single-pass Classify call driven by per-backend classifiers.
Controllers still own classification via the framework constructors
(NewUserError / NewRetryableError / NewDependencyError /
NewRetryableDependencyError); for errors a controller does not wrap,
the consumer now runs errs.Classify(err, classifiers...) once per
failing delivery, and downstream IsRetryable / IsUserError /
IsDependencyError become plain type checks.

errs.Classify walks the chain in two passes: pass 1 short-circuits on
any existing framework wrap so an explicit controller verdict always
wins; pass 2 runs the configured classifiers per node, outermost-first,
and prepends the matching framework wrap.

Adds two starter classifiers:

  - core/errs/generic — context.Canceled -> InfraRetryable so graceful
    shutdowns nack for redelivery instead of rejecting to DLQ.
  - core/errs/mysql — server error numbers, driver.ErrBadConn,
    sql.ErrConnDone/TxDone, and net.Error values. The classifier never
    returns User; constraint violations stay Infra and must be wrapped
    explicitly by the controller when they reflect bad user input.

Wires both into the orchestrator's consumer.New call.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sbalabanov sbalabanov marked this pull request as ready for review June 3, 2026 03:09
@sbalabanov sbalabanov requested review from a team and behinddwalls as code owners June 3, 2026 03:09
Comment thread core/errs/mysql/mysql.go
Comment thread core/errs/errs.go
// Pass 1 — cheap framework-wrap check. If any node already carries a
// framework type, the chain is interpretable as-is and classifiers are
// never invoked.
for cur := err; cur != nil; cur = errors.Unwrap(cur) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we expect mutli-errors to work in this case?

@behinddwalls behinddwalls enabled auto-merge June 3, 2026 05:23
@behinddwalls behinddwalls disabled auto-merge June 3, 2026 05:50
@behinddwalls behinddwalls merged commit e54cbaa into main Jun 3, 2026
13 of 14 checks passed
@behinddwalls behinddwalls deleted the errors branch June 3, 2026 05:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants