logs

package
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package logs owns the write side of a task's event history: it turns a node's event batch into rows, applies the status transitions those events imply, and fans the result out to live subscribers. Everything a client ever sees about a running task comes through here.

Index

Constants

View Source
const (
	KindProvisioning = "provisioning"
	KindPulling      = "pulling"
	KindStarted      = "started"
	KindLog          = "log"
	KindStep         = "step"
	KindArtifact     = "artifact"
	KindExited       = "exited"
	KindFinished     = "finished"
	KindError        = "error"
	KindMessage      = "message"
)

The canonical task_events.kind strings, matching podium.v1.TaskEventKind one for one.

View Source
const (
	RollupIntervalEnv = "PODIUM_LOG_ROLLUP_INTERVAL"
	RollupSettleEnv   = "PODIUM_LOG_ROLLUP_SETTLE"
	PruneIntervalEnv  = "PODIUM_LOG_PRUNE_INTERVAL"
	ChunkGraceEnv     = "PODIUM_LOG_CHUNK_GRACE"
)

Environment overrides for the roll-up schedule. They exist so the prune horizon can be driven to a second in a test without waiting a day, and so an operator with a small database can shorten it.

View Source
const FailureReasonOOM = "oom"

FailureReasonOOM is the tasks.failure_reason a task gets when its container was killed for exceeding its memory limit.

Variables

This section is empty.

Functions

func KindString

func KindString(k podiumv1.TaskEventKind) string

KindString is the stored spelling of a wire event kind.

Types

type Retries

type Retries interface {
	// Retry takes the task off the node it was on: queued again if max_attempts allows,
	// terminal with reason if it does not. Either way the task stops being the node's.
	Retry(ctx context.Context, taskID, reason string)
}

Retries hands a task back to whatever owns placement, after an error that ended the node's work on it without ending the task. The scheduler implements it: it owns the attempt budget, the lease and the queue, so the decision between another attempt and a terminal failure is not this package's to make.

type RollupConfig

type RollupConfig struct {
	// Interval is how often terminal tasks are swept for roll-up.
	Interval time.Duration
	// Settle is how long after a task finishes before its logs are rolled up. It keeps
	// the roll-up off the heels of the last event batch.
	Settle time.Duration
	// PruneInterval is how often rolled-up chunks are pruned.
	PruneInterval time.Duration
	// Grace is how long a task's chunks survive after its logs reached the object store.
	Grace time.Duration
}

RollupConfig is the log roll-up schedule.

Grace is the part that matters. A task's chunks are what store.TaskStreamOffsets and store.MaxTaskSeq are computed from, and those are what a restarting node is told to resume against, so deleting them is not a housekeeping detail. Roll-up only ever touches terminal tasks — which reconciliation never tells a node to adopt — and the grace period is the second belt: a task that finished minutes ago still has its hot rows if anything is still reading them.

func DefaultRollupConfig

func DefaultRollupConfig() RollupConfig

DefaultRollupConfig is the design's schedule: roll up a minute after a task settles, prune hourly, keep the hot rows for a day.

func RollupConfigFromEnv

func RollupConfigFromEnv() RollupConfig

RollupConfigFromEnv applies the four duration overrides to the defaults. An unparseable value is ignored: a typo must not silently delete a day of log retention.

type Service

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

Service ingests node event batches and serves StreamTaskEvents.

func New

func New(st *store.Store, logger *slog.Logger) *Service

New returns a Service. Call Run once to follow Postgres notifications.

func (*Service) Ingest

func (s *Service) Ingest(ctx context.Context, taskID string, batch []*podiumv1.TaskEvent) (uint64, error)

Ingest stores one node event batch and returns the highest seq it contained, which is what the caller acks. A node numbers all of a task's events from one seq space, so the batch is split across task_events and task_log_chunks but written in a single transaction — the ack therefore covers the whole batch, not either table's high-water mark.

Re-ingesting an acked batch is a no-op: the rows conflict on (task_id, seq) and the status transitions they imply are already applied and get rejected harmlessly.

func (*Service) Note

func (s *Service) Note(ctx context.Context, taskID, message string) error

Note appends one synthetic event to a task's history: something the control plane observed rather than the node reported. Losing a node is the case that matters — a task that simply stops, with nothing in its log to say why, is the single most confusing thing an operator can be shown.

It is stored as a non-retryable error event, which is how the CLI and the UI already render "this is why it ended", but it deliberately does *not* run the status transition such an event would imply when a node sends one: the caller owns the transition, and for a lost node the right end state is lost, not failed.

The sequence number is one past everything stored. That is safe precisely because the node whose events would have collided is gone; a node that comes back is handed the new high-water mark in its HelloAck and numbers above it.

func (*Service) PruneOnce

func (s *Service) PruneOnce(ctx context.Context) (int64, error)

PruneOnce deletes the hot rows of tasks rolled up longer ago than the grace period.

func (*Service) RollUpOnce

func (s *Service) RollUpOnce(ctx context.Context) (int, error)

RollUpOnce rolls up one batch of terminal tasks and reports how many it did.

func (*Service) Run

func (s *Service) Run(ctx context.Context) error

Run follows the task-event notification channel until ctx is cancelled, waking the subscribers of every task that gains rows. One subscription serves the whole process.

func (*Service) RunRollUp

func (s *Service) RunRollUp(ctx context.Context) error

RunRollUp sweeps terminal tasks into the object store and prunes the hot rows of ones that have been there long enough. It returns when ctx is cancelled.

func (*Service) SetArchive

func (s *Service) SetArchive(a *artifacts.Service, cfg RollupConfig)

SetArchive wires in the object store and the roll-up schedule. It is a setter for the same reason SetSlots is: the server builds the pieces in an order neither can be a constructor argument of.

func (*Service) SetRetries

func (s *Service) SetRetries(r Retries)

SetRetries wires in the scheduler, for the same reason SetSlots is a setter: the scheduler is built on the node registry, which is built on this service.

func (*Service) SetSlots

func (s *Service) SetSlots(sl Slots)

SetSlots wires in the node session registry. It is a setter rather than a constructor argument because the registry is built around this service: nodes.NewService takes the Ingestor, so neither can be constructed before the other.

func (*Service) Subscribe

func (s *Service) Subscribe(ctx context.Context, taskID string, fromSeq uint64) (<-chan *podiumv1.TaskEvent, error)

Subscribe replays a task's stored events from fromSeq (exclusive, so 0 replays everything) and then follows live ones. The returned channel is closed when the task is terminal and every event has been delivered, or when ctx is cancelled.

type Slots

type Slots interface {
	Release(taskID string)
}

Slots gives a node back the slot it was holding for a task. The node session registry implements it.

Jump to

Keyboard shortcuts

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