deploytimeline

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package deploytimeline folds the sources that describe one deploy (the attempt row, pipeline trace, gate events, probes, hook runs, build log and request metrics) into one ordered list of events, the same shape for a live stream and for a frozen replay.

Index

Constants

View Source
const (
	EnvRetention    = "APP_DEPLOY_TIMELINE_RETENTION"
	EnvMaxLogLines  = "APP_DEPLOY_TIMELINE_MAX_LOG_LINES"
	EnvImpactWindow = "APP_DEPLOY_TIMELINE_IMPACT_WINDOW"
	EnvActorWindow  = "APP_DEPLOY_TIMELINE_ACTOR_WINDOW"
	EnvSettleIdle   = "APP_DEPLOY_TIMELINE_SETTLE_IDLE"
)

Environment variables that tune the timeline. Each has a fallback so an unset variable never disables the feature.

Variables

This section is empty.

Functions

func CutoverAt

func CutoverAt(gate []store.DeployGateEvent, trace []store.DeployTraceStep) (time.Time, bool)

CutoverAt returns when traffic moved to the new release, from the gate timeline first and the pipeline trace otherwise.

func Settled

func Settled(in Inputs) bool

Settled reports whether nothing more will be added to the timeline, which is when it is safe to freeze it for replay.

Types

type Comparison

type Comparison struct {
	A      Timeline     `json:"a"`
	B      Timeline     `json:"b"`
	Phases []PhaseDelta `json:"phases"`
	// OnlyA and OnlyB list event codes seen in one deploy and not the other,
	// which is where a crashloop or a rollback shows up.
	OnlyA  []string     `json:"only_a"`
	OnlyB  []string     `json:"only_b"`
	Impact *ImpactDelta `json:"impact,omitempty"`
}

Comparison puts two timelines next to each other. Delta is B minus A.

func Compare

func Compare(a, b Timeline) Comparison

Compare lines up two timelines by phase.

type Config

type Config struct {
	Retention    time.Duration
	MaxLogLines  int
	ImpactWindow time.Duration
	ActorWindow  time.Duration
	SettleIdle   time.Duration
}

Config is the resolved tuning for one process.

func ConfigFromEnv

func ConfigFromEnv() Config

ConfigFromEnv reads the tuning variables.

type Event

type Event struct {
	ID         string       `json:"id"`
	At         time.Time    `json:"at"`
	Kind       Kind         `json:"kind"`
	Phase      Phase        `json:"phase"`
	Status     Status       `json:"status"`
	Code       string       `json:"code"`
	Title      string       `json:"title"`
	Detail     string       `json:"detail,omitempty"`
	Reason     string       `json:"reason,omitempty"`
	Service    string       `json:"service,omitempty"`
	Stream     string       `json:"stream,omitempty"`
	DurationMS int64        `json:"duration_ms,omitempty"`
	Trigger    *TriggerInfo `json:"trigger,omitempty"`
	Impact     *Impact      `json:"impact,omitempty"`
}

Event is one entry on the timeline. ID is stable for the same underlying fact, so a stream can send an event again only when its content changed.

func (Event) Signature

func (e Event) Signature() string

Signature changes whenever an event's visible content does. A log line's time is ignored: live lines carry a placeholder until the persisted log lands.

type Impact

type Impact struct {
	CutoverAt time.Time `json:"cutover_at"`
	WindowMS  int64     `json:"window_ms"`
	Complete  bool      `json:"complete"`
	Before    Window    `json:"before"`
	After     Window    `json:"after"`
}

Impact compares request health just before and just after cutover.

type ImpactDelta

type ImpactDelta struct {
	ErrorRate5xx float64 `json:"error_rate_5xx"`
	P95Ms        float64 `json:"p95_ms"`
	RatePerSec   float64 `json:"rate_per_sec"`
}

ImpactDelta is how the traffic shift differs between the two deploys.

type Inputs

type Inputs struct {
	Attempt store.DeployAttempt
	Trace   []store.DeployTraceStep
	Gate    []store.DeployGateEvent
	Probes  []store.ProbeAttempt
	Hooks   []store.HookRun
	Logs    []LogLine
	// Actor and ActorKind come from the audit trail when it matched.
	Actor     string
	ActorKind string
	Impact    *Impact
	// WatchOpen is true while the post-deploy watch can still trip.
	WatchOpen bool
	Now       time.Time
	Config    Config
}

Inputs are the raw sources for one deploy. Any of them may be empty: a deploy that never built has no log, one without a safety gate has no gate events.

type Kind

type Kind string

Kind groups events for rendering. The UI picks an icon per kind.

const (
	KindTrigger  Kind = "trigger"
	KindBuild    Kind = "build"
	KindLog      Kind = "log"
	KindPush     Kind = "image_push"
	KindHook     Kind = "hook"
	KindStep     Kind = "step"
	KindProbe    Kind = "readiness"
	KindCutover  Kind = "cutover"
	KindWatch    Kind = "watch"
	KindRollback Kind = "rollback"
	KindOutcome  Kind = "outcome"
	KindTraffic  Kind = "traffic_impact"
)

Event kinds.

type LogLine

type LogLine struct {
	At      time.Time
	Stream  string
	Message string
}

LogLine is one line of build output.

type Phase

type Phase string

Phase is the coarse stage an event belongs to; compare aligns on it.

const (
	PhaseTrigger   Phase = "trigger"
	PhaseBuild     Phase = "build"
	PhasePush      Phase = "push"
	PhaseHooks     Phase = "hooks"
	PhaseDeploy    Phase = "deploy"
	PhaseReadiness Phase = "readiness"
	PhaseCutover   Phase = "cutover"
	PhaseWatch     Phase = "watch"
	PhaseOutcome   Phase = "outcome"
)

Phases, in the order a deploy moves through them.

type PhaseDelta

type PhaseDelta struct {
	Phase   Phase  `json:"phase"`
	AMS     *int64 `json:"a_ms,omitempty"`
	BMS     *int64 `json:"b_ms,omitempty"`
	DeltaMS *int64 `json:"delta_ms,omitempty"`
}

PhaseDelta lines up one phase of two deploys. A side is nil when that deploy never reached the phase.

type PhaseSpan

type PhaseSpan struct {
	Phase      Phase     `json:"phase"`
	StartedAt  time.Time `json:"started_at"`
	EndedAt    time.Time `json:"ended_at"`
	DurationMS int64     `json:"duration_ms"`
}

PhaseSpan is the time one phase took.

type Status

type Status string

Status is the outcome of one event.

const (
	StatusRunning Status = "running"
	StatusOK      Status = "ok"
	StatusFailed  Status = "failed"
	StatusWarning Status = "warning"
	StatusInfo    Status = "info"
)

Event statuses.

type Timeline

type Timeline struct {
	DeployID   string      `json:"deploy_id"`
	App        string      `json:"app"`
	Verdict    Verdict     `json:"verdict"`
	Live       bool        `json:"live"`
	Frozen     bool        `json:"frozen"`
	FrozenAt   *time.Time  `json:"frozen_at,omitempty"`
	StartedAt  time.Time   `json:"started_at"`
	FinishedAt *time.Time  `json:"finished_at,omitempty"`
	Trigger    TriggerInfo `json:"trigger"`
	Events     []Event     `json:"events"`
	Phases     []PhaseSpan `json:"phases"`
	Impact     *Impact     `json:"impact,omitempty"`
	// LogsDropped counts build log lines left out to respect the line cap.
	LogsDropped int `json:"logs_dropped,omitempty"`
}

Timeline is the whole story of one deploy.

func Assemble

func Assemble(in Inputs) Timeline

Assemble builds the ordered timeline. It is pure: the same inputs always give the same events, so a stream can diff successive calls.

type TriggerInfo

type TriggerInfo struct {
	Source        string `json:"source"`
	Actor         string `json:"actor,omitempty"`
	ActorKind     string `json:"actor_kind,omitempty"`
	Branch        string `json:"branch,omitempty"`
	CommitSHA     string `json:"commit_sha,omitempty"`
	CommitMessage string `json:"commit_message,omitempty"`
	Author        string `json:"author,omitempty"`
	RerunOf       string `json:"rerun_of,omitempty"`
}

TriggerInfo says who or what started the deploy.

type Verdict

type Verdict string

Verdict is how the whole deploy ended up.

const (
	VerdictRunning    Verdict = "running"
	VerdictWatching   Verdict = "watching"
	VerdictSucceeded  Verdict = "succeeded"
	VerdictFailed     Verdict = "failed"
	VerdictRolledBack Verdict = "rolled_back"
	VerdictCanceled   Verdict = "canceled"
	VerdictQueued     Verdict = "queued"
)

Deploy verdicts.

type Window

type Window struct {
	From         time.Time `json:"from"`
	To           time.Time `json:"to"`
	HasTraffic   bool      `json:"has_traffic"`
	Requests     float64   `json:"requests"`
	RatePerSec   float64   `json:"rate_per_sec"`
	ErrorRate5xx float64   `json:"error_rate_5xx"`
	P95Ms        float64   `json:"p95_ms"`
}

Window is request health over one slice of time.

Jump to

Keyboard shortcuts

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