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

worker

package
v0.51.1 Latest Latest
Warning

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

Go to latest
Published: Oct 21, 2026 License: Apache-2.0, MIT Imports: 10 Imported by: 0

Documentation

Overview

Package worker is the production derive loop: it polls the dirty- session queue ingest feeds (see storage.DeriveQueue), debounces bursts, and re-derives one session at a time under a per-session advisory lock. It runs as its own process (`tapes serve derive-worker`) — NEVER inside the API container: a full derive once OOMKilled a 256Mi API pod, so derivation gets its own memory budget and processes exactly one session at a time.

Everything is at-least-once and leans on the deriver's idempotence (re-running an unchanged session prunes 0): a lost clear, a crashed derive, or a duplicate mark only costs a redundant derive.

Index

Constants

View Source
const (
	DefaultPollInterval   = 5 * time.Second
	DefaultDebounce       = 20 * time.Second
	DefaultMaxDeriveLag   = 45 * time.Second
	DefaultSweepInterval  = time.Hour
	DefaultPageSize       = 50
	DefaultMaxPollBackoff = 30 * time.Second
	DefaultDrainTimeout   = 30 * time.Second
	DefaultSweepWindow    = 24 * time.Hour
)

Defaults for Config fields left zero.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Project mirrors the ingest worker's configured project tag; it
	// does not participate in node hashes.
	Project string

	// PollInterval is how often the dirty queue is polled.
	PollInterval time.Duration

	// Debounce is how long a session's dirty mark must be quiet before
	// it derives — ingest bursts settle into one derive.
	Debounce time.Duration

	// SweepInterval is the slow backstop cadence: enqueue every session
	// present in the raw layer, catching lost marks. A sweep also runs
	// once at startup.
	SweepInterval time.Duration

	// MaxDeriveLag bounds debounce starvation: a continuously
	// streaming session re-marks on every capture and never settles,
	// so a mark that has waited this long derives anyway. Live views
	// see bounded lag instead of waiting for a quiet gap.
	MaxDeriveLag time.Duration

	// SweepWindow bounds the backstop sweep to sessions with raw
	// activity in the last window, so a worker restart in a large org
	// re-enqueues recent sessions instead of stampeding the queue with
	// all of history (default 24h). Negative disables the bound and
	// sweeps every session ever captured — the escape hatch for a full
	// re-derive after a deriver fix.
	SweepWindow time.Duration

	// PageSize bounds one poll's batch. Sessions are still derived
	// strictly one at a time.
	PageSize int32

	// MaxPollBackoff caps the jittered exponential backoff applied
	// between polls while the queue is unreachable (DB outage). The
	// first failure retries after roughly PollInterval; each further
	// consecutive failure doubles the delay up to this cap.
	MaxPollBackoff time.Duration

	// DrainTimeout bounds the graceful-shutdown window: after the run
	// context is canceled, the in-flight derive may keep running this
	// long before its store operations are aborted. Locks release
	// either way.
	DrainTimeout time.Duration

	// Metrics optionally injects a pre-built metrics surface so the
	// hosting command can mount /metrics (and serve health probes)
	// before the store is even reachable — e.g. while --wait-for-db
	// retries. NewWorker builds a fresh one when nil.
	Metrics *Metrics
}

Config tunes the worker loop. Zero fields take the package defaults.

type Metrics

type Metrics struct {

	// Derives counts per-session derive attempts by outcome:
	// ok / error / locked (another worker holds the session) /
	// skipped (cleared by a peer or re-dirtied inside the debounce).
	Derives *prometheus.CounterVec

	// Requeued counts successful derives whose conditional clear
	// matched nothing — the session was re-dirtied mid-derive and
	// stays queued.
	Requeued prometheus.Counter

	DeriveDuration prometheus.Histogram

	// UnknownCalls counts calls the classifier could not match to any
	// cataloged tell (derive.KindUnknown). A sustained non-zero rate
	// means the harness grew a new call shape the catalog is missing.
	UnknownCalls prometheus.Counter

	// ParseFailures counts raw rows whose request or response no
	// longer parses. Non-zero means a provider parser regressed or a
	// raw row predates a parser fix — the raw row is intact and
	// re-derivable later, but the signal deserves an alert.
	ParseFailures prometheus.Counter

	Sweeps        *prometheus.CounterVec
	SweepEnqueued prometheus.Counter

	PollErrors prometheus.Counter

	// ConsecutiveFailures mirrors the worker's in-memory outage
	// counter: non-zero means the queue is currently unreachable and
	// polls are backing off. Alert on sustained non-zero.
	ConsecutiveFailures prometheus.Gauge

	// QueueDepth and DeriveLag are refreshed once per successful poll:
	// how many sessions are dirty, and how stale the oldest dirty mark
	// is (now - oldest dirtied_at, seconds; 0 when the queue is empty).
	QueueDepth prometheus.Gauge
	DeriveLag  prometheus.Gauge
	// contains filtered or unexported fields
}

Metrics is the Prometheus surface for the derive worker. Each worker owns its own registry (same rationale as api.Metrics: tests scrape in isolation; the hosting command mounts Handler on its listener).

func NewMetrics

func NewMetrics() *Metrics

NewMetrics constructs the derive worker's counters on a fresh registry.

func (*Metrics) Handler

func (m *Metrics) Handler() http.Handler

Handler returns the /metrics scrape handler for this worker's registry.

func (*Metrics) Registry

func (m *Metrics) Registry() *prometheus.Registry

Registry exposes the registry so tests can scrape it.

type Store

type Store interface {
	// ListDeriveDirty returns dirty sessions that have settled OR
	// waited past the max-lag bound, oldest first.
	ListDeriveDirty(ctx context.Context, dirtiedBefore, firstDirtiedBefore time.Time, limit int32) ([]storage.DeriveQueueEntry, error)

	// GetDeriveDirty re-reads one queue entry (nil when clean).
	GetDeriveDirty(ctx context.Context, orgID, harnessID, harnessSessionID string) (*storage.DeriveQueueEntry, error)

	// ClearDeriveDirty removes the entry only if DirtiedAt is unchanged.
	ClearDeriveDirty(ctx context.Context, e storage.DeriveQueueEntry) (bool, error)

	// SweepDeriveDirty enqueues every raw-layer session active at or
	// after activeSince (zero time = everything).
	SweepDeriveDirty(ctx context.Context, activeSince time.Time) (int64, error)

	// DeriveQueueStats reports queue depth and the oldest dirty mark
	// (the worker's depth/lag gauges and readiness probe).
	DeriveQueueStats(ctx context.Context) (storage.DeriveQueueStats, error)

	// TryDeriveSessionLock takes the per-session advisory lock.
	// acquired=false (nil error) means another worker holds it.
	TryDeriveSessionLock(ctx context.Context, orgID, harnessID, harnessSessionID string) (release func(), acquired bool, err error)

	// RederiveSession re-derives and persists one harness session.
	RederiveSession(ctx context.Context, project, orgID, harnessID, harnessSessionID string) (*derive.RederiveReport, error)
}

Store is the storage capability surface the worker drives. The Postgres driver satisfies it; tests substitute a fake.

type Worker

type Worker struct {
	// contains filtered or unexported fields
}

Worker owns the poll/debounce/lock/derive/clear loop.

func NewWorker

func NewWorker(cfg Config, store Store, logger *slog.Logger) *Worker

NewWorker creates a derive worker. logger must be non-nil.

func (*Worker) Metrics

func (w *Worker) Metrics() *Metrics

Metrics exposes the worker's Prometheus surface so the hosting command can mount a scrape endpoint.

func (*Worker) Ready

func (w *Worker) Ready(ctx context.Context) error

Ready reports whether the worker can serve its purpose right now: the store answers and the dirty queue is pollable. This is the /readyz signal — it intentionally exercises the same query the poll loop depends on rather than a bare connection ping.

func (*Worker) Run

func (w *Worker) Run(ctx context.Context) error

Run blocks until ctx is canceled. One sweep runs immediately at startup (catching anything queued — or never queued — before this worker existed), then the poll and sweep tickers take over.

Shutdown is graceful: canceling ctx stops polling, but the in-flight derive keeps running on a detached context for up to DrainTimeout — finishing and clearing rather than aborting mid-write. A derive still running at the deadline is aborted; either way the advisory lock releases (release runs on a fresh background context) and Run returns nil.

Jump to

Keyboard shortcuts

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