forked from wrenn/wrenn
- Replace stale snapshot read (GetCurrentMetrics) with live query (GetLiveMetrics) against sandboxes table — always returns correct zeros when no capsules are running - Fix CPU reserved formula: running + starting only; paused VMs no longer contribute vCPUs (RAM reservation for paused unchanged) - Merge top cards into 3 paired Now/Peak cards with colored accent borders (green/blue/amber matching chart colors) - Move Live badge from Running Capsules card to page-level header - Add colored category dots to card and chart headers - Charts stacked vertically, flex-1 to fill remaining page height - vCPUs chart color changed to blue (#5a9fd4), RAM stays amber
139 lines
4.7 KiB
Go
139 lines
4.7 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)
|
|
+ CEIL(COALESCE(SUM(memory_mb) FILTER (WHERE status = 'paused'), 0)::NUMERIC / 2))::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 + ceil(paused/2) (capacity held for resume).
|
|
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)
|
|
+ CEIL(COALESCE(SUM(memory_mb) FILTER (WHERE status = 'paused'), 0)::NUMERIC / 2))::INTEGER AS memory_mb_reserved
|
|
FROM sandboxes
|
|
WHERE status IN ('running', 'starting', 'paused')
|
|
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.
|
|
// CPU reserved = running + starting only (paused VMs release CPU).
|
|
// RAM reserved = running + starting + ceil(paused/2) (capacity held for resume).
|
|
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
|
|
}
|