mirror of
https://github.com/coder/coder.git
synced 2026-10-31 19:36:41 +08:00
The usage generator writes `hb_agent_runtime_v1` rows with `created_at` at the UTC hourly bucket start and exactly one row per bucket, but nothing in the schema enforced either invariant. A duplicate bucket row under a different id would be double-counted by any consumer summing `runtime_ms`, and a misaligned `created_at` would skew which usage period a bucket is attributed to. This replaces the non-unique partial index `idx_usage_events_agent_runtime` (from migration 000561) with a unique index of the same shape and adds an hour-alignment `CHECK` constraint. Both statements validate existing rows: every supported writer has always produced conforming data, so a pre-existing violator is anomalous and failing the migration loudly beats silently rewriting usage rows. `generateBucket` treats a unique violation on the bucket index as another replica having won the race, mirroring the existing `ON CONFLICT (id)` no-op for committed rows. The `coderd/notifications` sync commit and its revert cancel out (the drift they addressed was fixed on main by #27979); the PR's net diff is only the usage-event changes. Part 1 of a 3-PR stack splitting up #27796 (see there for review history). Stack: this PR → #27984 → #27985.
25 lines
1.2 KiB
SQL
25 lines
1.2 KiB
SQL
-- The usage generator writes hb_agent_runtime_v1 rows with created_at at
|
|
-- the UTC hourly bucket start and exactly one row per bucket. Uniqueness
|
|
-- keeps any consumer that sums runtime_ms from counting a bucket twice;
|
|
-- the alignment CHECK protects the attribution model, which charges a
|
|
-- bucket to the usage period containing its start.
|
|
--
|
|
-- Both statements validate existing rows. Every supported writer has always
|
|
-- produced conforming data, so a pre-existing violator is anomalous and
|
|
-- failing the migration loudly beats silently rewriting usage rows.
|
|
ALTER TABLE usage_events
|
|
ADD CONSTRAINT usage_events_agent_runtime_hour_aligned
|
|
CHECK (
|
|
event_type <> 'hb_agent_runtime_v1'
|
|
OR date_trunc('hour', (created_at AT TIME ZONE 'UTC')) = (created_at AT TIME ZONE 'UTC')
|
|
);
|
|
|
|
-- Inserts keep their (id) arbiter: re-inserting a bucket under its
|
|
-- deterministic id stays a silent no-op, while a duplicate bucket row under
|
|
-- a different id raises a unique violation (generateBucket in
|
|
-- enterprise/coderd/usage/generator.go handles it).
|
|
DROP INDEX idx_usage_events_agent_runtime;
|
|
CREATE UNIQUE INDEX idx_usage_events_agent_runtime
|
|
ON usage_events (event_type, created_at)
|
|
WHERE event_type = 'hb_agent_runtime_v1';
|