Documentation
¶
Overview ¶
Package drain computes the fleet's parked-drain metrics from the persisted vehicle_state history and exposes them to Prometheus (D1, the instrument for the battery-drain experiment's Gate A).
Everything is derived from rows the recorder already writes; nothing here talks to Rivian, so computing it can't wake a car. The definitions match the ones already in use, so the gauges, the analysis queries and the Sleep chart agree:
- Parked drain (%/day): SoC lost over consecutive sample pairs where the car is parked (gear P or unknown, under 1 mph, not charging) at both ends, less than 24 h apart, with the odometer still (< 0.2 mi) and SoC moving less than 3 points (a bigger jump is an unrecorded charge or a calibration step, not drain). 24 × ΣΔSoC / Σhours. This is devils-advocate's D3 query.
- Idle-awake (h/day): hours awake while parked and not charging, per 24 h of recorded power state. Intervals are capped at 20 min and attributed to the state at their start, as in samples.SleepActivity, except that an unknown (NULL) gear or charging state counts as parked and not charging, as for drain.
- Sleeps: a sleep runs from the first 'sleep' sample after a non-sleep one to the next non-sleep sample. A quick re-wake is a sleep that lasted under 60 s (the sleep gate's failed sleep). A sleep counts in the window it ended in; one whose start is before the window, or which hasn't ended, isn't counted.
Index ¶
Constants ¶
const ( Window24h = "24h" Window7d = "7d" )
Windows the metrics are computed over.
const DefaultInterval = 15 * time.Minute
DefaultInterval is how often Run recomputes. The windows are 24 h and 7 d, so a quarter hour of lag is invisible; one fleet query per interval is cheap.
Variables ¶
This section is empty.
Functions ¶
func ParseInterval ¶
ParseInterval reads RIVOLT_DRAIN_METRICS_INTERVAL: empty means DefaultInterval; "0", "off" or "false" disable the metrics (ok = false); anything else is a Go duration, at least a minute. An unparsable value falls back to the default and returns the error for the caller to log.
Types ¶
type Collector ¶
type Collector struct {
// contains filtered or unexported fields
}
Collector serves the last computed snapshot to Prometheus. Run refreshes it; scrapes never touch the database. Series for a vehicle with no rows in the last 7 days disappear on the next refresh.
One replica (the holder of a Postgres advisory lock) computes and exports the fleet-wide series; the others export nothing, so a pod that lost the lock can't keep serving stale numbers. The 7-day fleet scan is the cost, and it would otherwise double with every replica. Failover is within one interval after the leader pod goes away. Query the series aggregated, max by (vehicle, window), as the parked-drain Grafana dashboard does; never sum them.
The vehicle label is the Rivian vehicle id. That's fine for the admin-only Grafana these feed, but keep these series off any public or shared dashboard.
func NewCollector ¶
func NewCollector() *Collector
NewCollector returns a Collector with no data yet.
func (*Collector) Collect ¶
func (c *Collector) Collect(ch chan<- prometheus.Metric)
Collect implements prometheus.Collector.
func (*Collector) Describe ¶
func (c *Collector) Describe(ch chan<- *prometheus.Desc)
Describe implements prometheus.Collector.
func (*Collector) Run ¶
func (c *Collector) Run(ctx context.Context, db *sql.DB, interval time.Duration, logger *slog.Logger)
Run recomputes now and then every interval until ctx is done, while this replica holds the leader lock. Without it the snapshot is cleared (the replica exports no drain series) and the next tick tries again. A failed recompute keeps the previous snapshot (its last-success timestamp ages, which is what to alert on), gives the lock up with the connection, and retries on the next tick.
type Querier ¶ added in v0.38.0
type Querier interface {
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
}
Querier is what Compute reads through: a *sql.DB, or the *sql.Conn the collector holds its leader lock on.
type Stat ¶
type Stat struct {
VehicleID string // Rivian vehicle id, as in the logs
Window string // Window24h | Window7d
// ParkedHours is the parked time the drain rate is measured over.
ParkedHours float64
// DrainPctPerDay is nil when ParkedHours is under the window's
// minimum.
DrainPctPerDay *float64
// ObservedHours is the time with a recorded power state.
ObservedHours float64
// IdleAwakeHPerDay is nil when ObservedHours is under the minimum.
IdleAwakeHPerDay *float64
Sleeps int
QuickRewakes int
// MedianSleep is nil when no sleep ended in the window.
MedianSleep *time.Duration
}
Stat is one vehicle's metrics over one window.