forked from wrenn/wrenn
SampleSandboxMetrics previously filtered WHERE status IN ('running',
'starting', 'paused'), which returned no rows when all capsules were
stopped. This caused zero snapshots to be skipped, leaving the
time-series charts with no trailing data points instead of showing
the expected zero values.
Remove the WHERE filter so the query groups by all teams that have
any sandbox row. The per-status FILTER clauses on the aggregates
already produce correct zero counts for stopped capsules.
Also includes the per-VM RAM ceiling formula change (sum(ceil(each/2))
instead of ceil(sum/2)).
141 lines
4.9 KiB
Go
141 lines
4.9 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.30.0
|
|
// source: metrics.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
)
|
|
|
|
const getLiveMetrics = `-- name: GetLiveMetrics :one
|
|
SELECT
|
|
(COUNT(*) FILTER (WHERE status IN ('running', 'starting')))::INTEGER AS running_count,
|
|
(COALESCE(SUM(vcpus) FILTER (WHERE status IN ('running', 'starting')), 0))::INTEGER AS vcpus_reserved,
|
|
(COALESCE(SUM(memory_mb) FILTER (WHERE status IN ('running', 'starting')), 0)
|
|
+ COALESCE(SUM(CEIL(memory_mb::NUMERIC / 2)) FILTER (WHERE status = 'paused'), 0))::INTEGER AS memory_mb_reserved
|
|
FROM sandboxes
|
|
WHERE team_id = $1
|
|
`
|
|
|
|
type GetLiveMetricsRow struct {
|
|
RunningCount int32 `json:"running_count"`
|
|
VcpusReserved int32 `json:"vcpus_reserved"`
|
|
MemoryMbReserved int32 `json:"memory_mb_reserved"`
|
|
}
|
|
|
|
// Reads directly from sandboxes for accurate real-time current values.
|
|
// CPU reserved = running + starting only (paused VMs release CPU).
|
|
// RAM reserved = running + starting + sum(ceil(each_paused/2)) (per-VM ceiling).
|
|
func (q *Queries) GetLiveMetrics(ctx context.Context, teamID string) (GetLiveMetricsRow, error) {
|
|
row := q.db.QueryRow(ctx, getLiveMetrics, teamID)
|
|
var i GetLiveMetricsRow
|
|
err := row.Scan(&i.RunningCount, &i.VcpusReserved, &i.MemoryMbReserved)
|
|
return i, err
|
|
}
|
|
|
|
const getPeakMetrics = `-- name: GetPeakMetrics :one
|
|
SELECT
|
|
COALESCE(MAX(running_count), 0)::INTEGER AS peak_running_count,
|
|
COALESCE(MAX(vcpus_reserved), 0)::INTEGER AS peak_vcpus,
|
|
COALESCE(MAX(memory_mb_reserved), 0)::INTEGER AS peak_memory_mb
|
|
FROM sandbox_metrics_snapshots
|
|
WHERE team_id = $1
|
|
AND sampled_at > NOW() - INTERVAL '30 days'
|
|
`
|
|
|
|
type GetPeakMetricsRow struct {
|
|
PeakRunningCount int32 `json:"peak_running_count"`
|
|
PeakVcpus int32 `json:"peak_vcpus"`
|
|
PeakMemoryMb int32 `json:"peak_memory_mb"`
|
|
}
|
|
|
|
func (q *Queries) GetPeakMetrics(ctx context.Context, teamID string) (GetPeakMetricsRow, error) {
|
|
row := q.db.QueryRow(ctx, getPeakMetrics, teamID)
|
|
var i GetPeakMetricsRow
|
|
err := row.Scan(&i.PeakRunningCount, &i.PeakVcpus, &i.PeakMemoryMb)
|
|
return i, err
|
|
}
|
|
|
|
const insertMetricsSnapshot = `-- name: InsertMetricsSnapshot :exec
|
|
INSERT INTO sandbox_metrics_snapshots (team_id, running_count, vcpus_reserved, memory_mb_reserved)
|
|
VALUES ($1, $2, $3, $4)
|
|
`
|
|
|
|
type InsertMetricsSnapshotParams struct {
|
|
TeamID string `json:"team_id"`
|
|
RunningCount int32 `json:"running_count"`
|
|
VcpusReserved int32 `json:"vcpus_reserved"`
|
|
MemoryMbReserved int32 `json:"memory_mb_reserved"`
|
|
}
|
|
|
|
func (q *Queries) InsertMetricsSnapshot(ctx context.Context, arg InsertMetricsSnapshotParams) error {
|
|
_, err := q.db.Exec(ctx, insertMetricsSnapshot,
|
|
arg.TeamID,
|
|
arg.RunningCount,
|
|
arg.VcpusReserved,
|
|
arg.MemoryMbReserved,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const pruneOldMetrics = `-- name: PruneOldMetrics :exec
|
|
DELETE FROM sandbox_metrics_snapshots
|
|
WHERE sampled_at < NOW() - INTERVAL '60 days'
|
|
`
|
|
|
|
func (q *Queries) PruneOldMetrics(ctx context.Context) error {
|
|
_, err := q.db.Exec(ctx, pruneOldMetrics)
|
|
return err
|
|
}
|
|
|
|
const sampleSandboxMetrics = `-- name: SampleSandboxMetrics :many
|
|
SELECT
|
|
team_id,
|
|
(COUNT(*) FILTER (WHERE status IN ('running', 'starting')))::INTEGER AS running_count,
|
|
(COALESCE(SUM(vcpus) FILTER (WHERE status IN ('running', 'starting')), 0))::INTEGER AS vcpus_reserved,
|
|
(COALESCE(SUM(memory_mb) FILTER (WHERE status IN ('running', 'starting')), 0)
|
|
+ COALESCE(SUM(CEIL(memory_mb::NUMERIC / 2)) FILTER (WHERE status = 'paused'), 0))::INTEGER AS memory_mb_reserved
|
|
FROM sandboxes
|
|
GROUP BY team_id
|
|
`
|
|
|
|
type SampleSandboxMetricsRow struct {
|
|
TeamID string `json:"team_id"`
|
|
RunningCount int32 `json:"running_count"`
|
|
VcpusReserved int32 `json:"vcpus_reserved"`
|
|
MemoryMbReserved int32 `json:"memory_mb_reserved"`
|
|
}
|
|
|
|
// Aggregates per-team resource usage from the live sandboxes table.
|
|
// Groups by all teams that have any sandbox row (including stopped) so that
|
|
// zero-value snapshots are recorded when all capsules are stopped, keeping the
|
|
// time-series charts continuous rather than trailing off into empty space.
|
|
// CPU reserved = running + starting only (paused VMs release CPU).
|
|
// RAM reserved = running + starting + sum(ceil(each_paused/2)) (per-VM ceiling).
|
|
func (q *Queries) SampleSandboxMetrics(ctx context.Context) ([]SampleSandboxMetricsRow, error) {
|
|
rows, err := q.db.Query(ctx, sampleSandboxMetrics)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var items []SampleSandboxMetricsRow
|
|
for rows.Next() {
|
|
var i SampleSandboxMetricsRow
|
|
if err := rows.Scan(
|
|
&i.TeamID,
|
|
&i.RunningCount,
|
|
&i.VcpusReserved,
|
|
&i.MemoryMbReserved,
|
|
); err != nil {
|
|
return nil, err
|
|
}
|
|
items = append(items, i)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
return items, nil
|
|
}
|