Documentation
¶
Overview ¶
Package errorhandling is the compiled source for docs/guide/error-handling.md.
Index ¶
- Constants
- func ExecuteWithClassification(transient bool) error
- func Reducer(reporter *Reporter) live.Reducer[State, live.AnonymousIdentity]
- func Start[S any, I live.IIdentity](cfg live.Config[S, I]) (*live.App[S, I], error)
- func WasTransient(err error) bool
- func WireLogging(cfg live.Config[State, live.AnonymousIdentity], r *Reporter, ...) live.Config[State, live.AnonymousIdentity]
- type Reporter
- type State
Constants ¶
const SourceFetch = "report.fetch"
SourceFetch is the source of the effect whose failure this reducer knows how to handle. It is the value live.EffectFailedSourceField carries, which is what the reducer matches on.
Variables ¶
This section is empty.
Functions ¶
func ExecuteWithClassification ¶
ExecuteWithClassification shows both sides of the retry mark.
Retryable marks an error returned from an effect's Run as transient. The unmarked default is terminal, deliberately: an effect may have committed externally before it failed, so retrying a failure nobody classified risks doing it twice. Between a visible omission and an invisible duplicate, the default belongs on the omission.
func Reducer ¶
Reduce handles the failure event — and does not log it.
A failed or panicking effect is delivered as an ordinary event named live.EffectFailedEvent, carrying three fields. The name is a library constant and not a string to type: an application that hard-codes it and gets it wrong ships a failure path that never runs, and its tests pass because the reducer's default branch does nothing.
What this function may do with those three fields is fixed by FR-14 and FR-16 rather than by taste. It may branch on them and it may put them in state; it may not log them, because FR-16 names "logging of application data" as I/O and a reducer performs no I/O. The reason is replay and not tidiness: a log call in here makes the same event log produce a different sequence of records on every run, and determinism is the property the reducer is written for. Reporter.FetchEffect below is where this application's record of the failure is written.
func Start ¶
Start reports a configuration failure the way it is worth reporting.
live.New returns a *live.ConfigError naming the field at fault and what to set it to. Every configuration mistake is a startup failure rather than a session that misbehaves later, so this is a failed deploy and not a pager at three in the morning.
func WasTransient ¶
WasTransient reads the mark back off an error the caller already holds.
It is the reader for code that holds the error — an executor deciding between its own retry and handing the decision up, and the spec that checks it decided correctly. The reader for a reducer is the field on the failure event, because what a reducer holds is an event.
The mark is found through errors.As, so it survives arbitrary %w wrapping in either direction, and it is invisible in the message.
func WireLogging ¶
func WireLogging(cfg live.Config[State, live.AnonymousIdentity], r *Reporter, logger *slog.Logger) live.Config[State, live.AnonymousIdentity]
WireLogging sets both halves, because the two halves of a failed effect are logged by two different parties.
An effect that returns an error is logged by the Run above; the library adds nothing. An effect that PANICS never reaches that line — the library recovers it, logs it at error level to Config.Logger with the session, the effect source, the event that scheduled it and the stack, and synthesizes the same failure event, classified terminal. So an application whose effects log their own errors and whose Config leaves Logger nil has logged one half of its effect failures and dropped the other half silently.
Types ¶
type Reporter ¶
type Reporter struct {
// Log is the application's own logger. It may be the same *slog.Logger
// handed to Config.Logger; the library's records carry their own names.
Log *slog.Logger
// Fetch is the I/O this effect performs.
Fetch func(context.Context) error
}
Reporter performs the effect, and is where its failure is logged.
This is the home the reducer cannot be, and the move is one hop: an effect's Run executes on the session actor after the reducer returned, which is exactly what FR-16 means by "the actor boundary". It is also the better place on the evidence rather than merely the legal one — it holds the error value, so it can classify it, unwrap it, or pull structured fields off it with errors.As, none of which is available from the flattened string the failure event carries.
func (*Reporter) FetchEffect ¶
func (r *Reporter) FetchEffect() live.Effect[live.AnonymousIdentity]
FetchEffect is the effect, and the place its failure is logged.
The library writes no record of an error an effect returns: it turns the error into the reducer's live.EffectFailedEvent and counts it in gotthlive_effects_total{result="error"} when Config.Metrics is set. This log line is the only one there will be, which is why it belongs here and not in the reducer that reads the event afterwards.