Admin: leases, pin, release, drain, usage, metrics

cmd/crossbar/main.go calls admin.Handler with the new 6-arg signature, passing nil for the not-yet-wired leases/limiter/store/drainer (task 07 wires them) so go vet and go test ./... pass on cmd/crossbar. This is a compile fix, not the task-07 wiring; noted in the implementer-log.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
2026-09-25 06:33:29 -07:00
parent c2a8b88a3f
commit 32ac7f549a
9 changed files with 808 additions and 97 deletions
+12
View File
@@ -141,6 +141,18 @@ func scanUsage(rows *sql.Rows) ([]UsageRow, error) {
return out, rows.Err()
}
func scanStatusCounts(rows *sql.Rows) ([]StatusCount, error) {
var out []StatusCount
for rows.Next() {
var c StatusCount
if err := rows.Scan(&c.Route, &c.Host, &c.Status, &c.Count); err != nil {
return nil, wrap(err)
}
out = append(out, c)
}
return out, rows.Err()
}
func scanEvents(rows *sql.Rows) ([]LeaseEvent, error) {
var out []LeaseEvent
for rows.Next() {
+25
View File
@@ -95,6 +95,14 @@ func (u UsageRow) CacheHitRatio() float64 {
return float64(u.CachedTokens) / float64(u.PromptTokens)
}
// StatusCount is one (route, host, status) group of live requests, for the metrics endpoint, which
// needs the per-status breakdown Usage cannot give.
type StatusCount struct {
Route, Host string
Status int
Count int64
}
// Store holds the SQLite connection to crossbar's durable state.
type Store struct {
db *sql.DB
@@ -232,6 +240,23 @@ func (s *Store) Usage(since time.Time, by By) ([]UsageRow, error) {
return scanUsage(rows)
}
// StatusCounts groups the live requests at or after since by (route, host, status). It reads the
// requests table only; the rolled-up requests_daily rows are not in it (Prune has moved them out of
// requests), so counts cover only traffic still in the live table.
func (s *Store) StatusCounts(since time.Time) ([]StatusCount, error) {
sinceMs := since.UnixMilli()
rows, err := s.db.Query(`
SELECT route, host, status, COUNT(*)
FROM requests WHERE started >= ?
GROUP BY route, host, status
ORDER BY route, host, status`, sinceMs)
if err != nil {
return nil, wrap(err)
}
defer rows.Close()
return scanStatusCounts(rows)
}
// Events returns lease events at or after since, oldest first, at most limit.
func (s *Store) Events(since time.Time, limit int) ([]LeaseEvent, error) {
rows, err := s.db.Query(`