textmachine/platform/internal/pgstore/migrations/00009_runner.sql

75 lines
4.7 KiB
SQL

-- +goose Up
-- The runner's half of a run: what the platform must know to spawn a transient systemd unit, to
-- tail the engine's journal into this database, and to find out what happened to a unit it was not
-- watching. The engine is NOT a child of this service (D39.106 §2), so every fact below has to
-- survive the platform being restarted in the middle of the run that produced it.
-- The ceiling of the run, in CHAPTERS: the unit the user chooses (D39.110 §2a). The money it is
-- worth is not stored here, because it is not a property of the run's intent — the reservation row
-- holds the amount that was actually taken.
alter table runs add column ceiling_chapters integer not null default 0;
-- Machine reason a run is paused, exactly the contract's PausedReason vocabulary. The DDL checks it
-- because this value is produced by our own materializer: an unknown one is a defect, not data.
alter table runs add column paused_reason text check (paused_reason in ('credit_exhausted'));
-- When the money of this run was resolved. A run can be finished (the process is gone) and still
-- unsettled (the hold is open) — those are different questions and the reconciler answers the
-- second one on a retry, so it needs its own column rather than an inference from finished_at.
alter table runs add column settled_at timestamptz;
-- One transient unit per ATTEMPT, and everything needed to reason about it after a reboot.
alter table run_attempts
-- The transient unit's name. systemd's own state is not the truth (research/25 §Опс): the unit
-- is started with --collect, so it is unloaded the moment it exits and `show` then answers
-- "not-found" for a run that finished cleanly and for one that never existed alike.
add column unit_name text,
-- The VERSIONED path of the engine binary this attempt was pinned to (unified backlog row 139).
-- The engine ships more often than a run finishes, so "the current binary" is not a stable
-- answer; a resume uses the pinned path unless a resume with another version is asked for
-- explicitly.
add column engine_binary text not null default '',
-- The ceiling handed to the engine for this attempt, in micro-USD. Kept because the hold can be
-- released while the process is still exiting, and "what was this attempt allowed to spend" has
-- to remain answerable afterwards.
add column ceiling_micro_usd bigint not null default 0,
-- Byte offset of the journal the cursor stands at. A HINT, not the cursor: the cursor of record
-- is (engine_run_id, seq) (D39.106 §2). A hint that lands mid-file is simply where reading
-- starts; what the cursor of record then does with the lines is decide them — a duplicate seq is
-- skipped, a gap stops the projection of the attempt. It is NOT "the file is re-read from the
-- start": that was written before the tailer was, and the register carries the correction.
add column last_offset bigint not null default 0,
-- SHA-256 of the line that moved last_seq. Delivery is at-least-once and a duplicate seq is
-- NORMAL (PD-105); the same seq carrying a DIFFERENT payload is not, and it is the only form of
-- corruption a high-water mark cannot see on its own.
add column last_line_sha256 bytea,
-- Cumulative spend as the engine last reported it, in micro-USD. Freshness only: the balance is
-- protected by the hold and by the ceiling the engine enforces itself (D39.84/D39.100).
add column spend_micro_usd bigint not null default 0,
-- Set when materialization of this attempt was stopped on purpose. A quarantined attempt keeps
-- RUNNING — the engine is not ours to kill over our own inability to read its journal — and its
-- state is then only as fresh as the resync channel makes it.
add column quarantine_reason text,
-- What systemd said the unit's end was: $SERVICE_RESULT from ExecStopPost (success, exit-code,
-- oom-kill, timeout, …). The exit CODE alone cannot distinguish "the engine exited 1" from "the
-- kernel killed it", and the two lead to different next actions.
add column exit_result text;
-- Finding the live attempt of a run is on the hot path of every sweep of the reconciler.
create index run_attempts_live_idx on run_attempts (run_id) where ended_at is null;
-- +goose Down
drop index run_attempts_live_idx;
alter table run_attempts
drop column exit_result,
drop column quarantine_reason,
drop column spend_micro_usd,
drop column last_line_sha256,
drop column last_offset,
drop column ceiling_micro_usd,
drop column engine_binary,
drop column unit_name;
alter table runs drop column settled_at;
alter table runs drop column paused_reason;
alter table runs drop column ceiling_chapters;