textmachine/platform/internal/pgstore/observe.go

48 lines
2 KiB
Go

package pgstore
import (
"context"
"fmt"
)
// Observations is one reading of the state an operator cannot otherwise see.
//
// Every figure here used to be answerable only by opening psql (zone backlog П-11): how much work is
// queued, whether money is stuck in a hold nothing closes, whether a live run's projection has been
// blinded, how many books are stuck in intake. They are read in ONE statement because a set of them
// taken at different moments describes a state the system was never in.
type Observations struct {
QueueDepth int64
OldestHoldSeconds float64
QuarantinedAttempts int64
LiveRuns int64
BooksUploading int64
BooksParsing int64
}
// Observe reads the control plane's own state.
//
// The queue's table is asked for through to_regclass rather than assumed: River owns that schema and
// migrates it separately (STACK_DECISIONS §19), so an instance whose queue migration has not run
// answers a readiness probe about it and must not fail its telemetry over it as well.
func (s *Store) Observe(ctx context.Context) (Observations, error) {
const q = `
select
(select case when to_regclass('river_job') is null then 0 else
(select count(*) from river_job
where state in ('available', 'running', 'scheduled', 'retryable', 'pending')) end),
(select coalesce(extract(epoch from (now() - min(opened_at))), 0)
from reservations where state = 'open'),
(select count(*) from run_attempts
where quarantine_reason is not null and ended_at is null),
(select count(*) from runs where finished_at is null),
(select count(*) from books where status = 'uploading'),
(select count(*) from books where status = 'parsing')`
var o Observations
err := s.pool.QueryRow(ctx, q).Scan(&o.QueueDepth, &o.OldestHoldSeconds, &o.QuarantinedAttempts,
&o.LiveRuns, &o.BooksUploading, &o.BooksParsing)
if err != nil {
return Observations{}, fmt.Errorf("pgstore: observe: %w", err)
}
return o, nil
}