Help us shape the future of Go! Take the 2026 Go Developer Survey

lifecycle

package
v1.54.0 Latest Latest
Warning

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

Go to latest
Published: Sep 17, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package lifecycle classifies "why did this goroutine generation end" from several independent local signals (a deliberate-close flag, a clean-exit flag, ctx.Err()) into a closed Reason, so a subsystem's reconnect/exit- callback decision is one function call instead of a boolean-OR of flags. See project_plans/session-lifecycle-state-machine for the motivating incidents.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AwaitBounded

func AwaitBounded(done <-chan struct{}, wait time.Duration) bool

AwaitBounded waits for done to close, returning true if it does before wait elapses and false otherwise. Generalizes the bounded-wait-then- abandon idiom needed when tearing down a generation whose goroutine may be blocked on a read Go cannot forcibly interrupt.

func EndGeneration

func EndGeneration(span trace.Span, subsystem string, reason Reason)

EndGeneration tags span with reason, ends it, increments session_lifecycle_ends_total, and decrements session_lifecycle_active_generations. Pairs with StartGeneration.

func IsBenignTimeout

func IsBenignTimeout(err error) bool

IsBenignTimeout reports whether err is an expected poll-timeout rather than a real disconnect: a net.Error with Timeout() true, os.ErrDeadlineExceeded, or io.ErrUnexpectedEOF (a partial read before the deadline fired). Ports exactly the three typed checks session/external_streamer.go used inline, deliberately without a strings.Contains fallback — a classifier that falls through to matching error text silently breaks if a wrapped library changes its message.

func RecordEnd

func RecordEnd(ctx context.Context, subsystem string, reason Reason)

RecordEnd is a lighter-weight alternative to EndGeneration for a lifecycle-ending decision that does not own a dedicated generation span (e.g. a reconnect loop's own give-up branches, running mid-generation on an already-open span). Adds a span event on ctx's current span, if any — a no-op otherwise — plus the same counter increment as EndGeneration. It does not touch the active-generations gauge: callers of RecordEnd never called StartGeneration, so there is nothing to decrement.

func RegisterMetrics

func RegisterMetrics() error

RegisterMetrics registers the session_lifecycle_* instruments against telemetry.GetMeter(). Idempotent via sync.Once — package init already calls this once; exported so a test can call it again safely.

func StartGeneration

func StartGeneration(ctx context.Context, subsystem string) (context.Context, trace.Span)

StartGeneration opens one observability span for one goroutine- generation's lifetime and increments session_lifecycle_active_generations for subsystem. Pair with EndGeneration.

Types

type Reason

type Reason int

Reason is a closed enum representing why a goroutine-lifecycle generation ended. Its zero value, ReasonUnknown, is safe by default: any code path that never explicitly classifies a reason (a forgotten assignment, or a future variant added without updating a predicate's switch) is treated as "stop, and notify" by ShouldContinue/ShouldFireExitCallback respectively, rather than silently reconnecting or silently swallowing an exit. Mirrors session/detection.DetectedStatus's iota-plus-exhaustive-linter idiom (see .golangci.yml's exhaustive carve-out for this package).

const (
	// ReasonUnknown is Reason's zero value — see the type doc comment.
	ReasonUnknown Reason = iota
	// ReasonDeliberateClose means the whole session/session-owner is ending
	// on purpose.
	ReasonDeliberateClose
	// ReasonDeliberateSupersede means this generation is being torn down
	// deliberately for a reopen, but the owning session is not closing.
	ReasonDeliberateSupersede
	// ReasonCleanExit means the remote side already reported a clean exit
	// before this generation's read/receive failed.
	ReasonCleanExit
	// ReasonTransportDrop means an unexpected, non-deliberate stream/process
	// end — the only Reason for which ShouldContinue() returns true.
	ReasonTransportDrop
	// ReasonReconnectExhausted means a reconnect loop ran out of attempts
	// without reconnecting, as opposed to being interrupted by a deliberate
	// close.
	ReasonReconnectExhausted
)

func (Reason) ShouldContinue

func (r Reason) ShouldContinue() bool

ShouldContinue reports whether the calling goroutine should attempt to reconnect/retry for this Reason. Only ReasonTransportDrop returns true; every other value — including ReasonUnknown and any unhandled future variant — returns false (fail toward stopping).

func (Reason) ShouldFireExitCallback

func (r Reason) ShouldFireExitCallback() bool

ShouldFireExitCallback reports whether a one-shot exit callback should fire for this Reason. Only ReasonDeliberateClose returns false; every other value — including ReasonUnknown and any unhandled future variant — returns true (fail toward notifying, since a silently-swallowed exit is the worse outcome for a one-shot callback contract).

func (Reason) String

func (r Reason) String() string

String returns r's snake_case label for use as a span/metric attribute value. An unhandled value returns "unknown", matching ReasonUnknown's label.

Jump to

Keyboard shortcuts

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