Documentation
¶
Overview ¶
Package phasetracking accumulates cumulative time-in-phase for instance lifecycle phases. The tracker is embedded in instance metadata and updated at every externally-observable state transition so consumers can use the resulting durations for billing, observability, and analytics.
Phases mirror the externally-observable values of instances.State (lowercased so they remain stable in the API surface even if the internal enum is renamed). The Initializing→Running transition is detected lazily when guest boot markers are persisted, so the tracker reflects the same view of guest readiness that the public State machine reports — not the bare moment the VMM process came up.
Transient internal substates that no external observer can see — for example the Paused/Shutdown steps inside a single Standby or Stop orchestration — are intentionally not recorded; they would be sub-millisecond blips inside a non-yielding function call that adds noise without truth.
Only the transition orchestration sites in lib/instances should call Record. The tracker intentionally does not subscribe to the lifecycle event bus — that bus is best-effort and lossy, which is unsuitable for billing.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Phase ¶
type Phase string
Phase is the canonical lifecycle phase name. Values mirror instances.State lowercased so they remain stable in the API surface even if the internal State enum is renamed.
type Tracker ¶
type Tracker struct {
Current Phase `json:"current,omitempty"`
Since time.Time `json:"since,omitempty"`
Cumulative map[Phase]int64 `json:"cumulative,omitempty"`
}
Tracker accumulates cumulative wall-clock time spent in each phase.
Invariants:
- Cumulative[phase] is the total ms spent in `phase` across all prior completed visits to that phase.
- Time spent in the *current* phase (since `Since`) is NOT yet rolled into Cumulative — callers that want "live" totals should use Snapshot.
- Current and Since must be updated atomically with Cumulative; that's the contract of Record. Direct mutation is not supported.
The zero value is valid: it represents an instance that has not entered any phase yet. The first Record call sets Current and Since without accruing time (there is no prior phase to accrue from).
func (Tracker) Clone ¶
Clone returns a deep copy of the tracker. The returned tracker shares no state with the receiver, so independent Record/Reset calls do not interfere.
func (*Tracker) Record ¶
Record transitions into newPhase as of `now`, first accruing time-in-current into Cumulative. Safe to call on a zero-value Tracker (first transition has no prior phase, so no accrual happens).
`now` is a parameter rather than time.Now() so tests can pin time and so callers can use the same `now` value they're persisting elsewhere on the metadata (e.g. StartedAt) without drift.