Skip to content

Handle a degraded construction

bus, err := messaging.New(backend, settings)

Both return values can be meaningful at once. The bus is complete and correct for everything that was applied; the error is the complete list of what was not.

The conservative path costs you nothing

bus, err := messaging.New(backend, settings)
if err != nil {
    return err
}

This is correct and is what most services should do. The degraded path is available only to callers who look for it, so nothing is made worse for anybody by its existing.

The degraded path

bus, err := messaging.New(backend, settings)
if bus == nil {
    return err // fatal: nothing usable was built
}

if err != nil {
    log.Warn("messaging started with settings the backend could not apply", "detail", err)
}

The test is bus == nil, not err != nil. A nil bus means a fatal problem; a non-nil bus with an error means it is running with less than you asked for.

What degrades, and what is fatal

The line is ownership, not severity.

Setting Class
An overflow policy the backend does not offer degraded
A wildcard pattern on a backend with no pattern support fatal
A delivery mode the backend does not declare fatal
AtLeastOnce on a backend that does not survive a restart, without AllowVolatile fatal
ExtendLease on a backend that cannot extend a lease fatal
StartAt: AllAvailable on a backend declaring no replay fatal
A subscription that cannot be bounded fatal
Discards that cannot be counted or attributed fatal
An invalid subject pattern fatal
A competing subscription with no group fatal
Two subscriptions with the same name fatal
No backend at all fatal
No subscription declared at all fatal

Overflow is the one setting that degrades; every other capability mismatch above is fatal, because a delivery guarantee, a pattern language or a lease is a promise this module makes to a handler's author, and downgrading one silently changes what that handler is entitled to assume without telling them. A backend declining an overflow policy changes only what happens at a full queue, which is visible and countable either way. See what happens at a full queue.

Two properties worth relying on

A degraded setting is not applied at all — not substituted, clamped or approximated. Asking for ShedOldest on a backend that cannot do it gets that backend's native behaviour, because delivering a value nobody requested while reporting success for that field is worse than saying plainly that it was dropped.

The error names every problem, not the first. Three unsupported settings produce one error naming all three, rather than one round trip at a time.

An unreachable backend is not a construction failure

Construction does not connect, deliberately, so that a briefly unavailable cluster does not stop your application booting. Unreachability shows up exactly once, where you are already looking: Ready() does not close and your own timeout fires.