mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add logical-attribution storage observability, grouped by (community_id, actor_pubkey): a partial index on audit_log for media_uploaded actions, per-user/per-community/fleet byte and object gauges in the usage poller, and a real-time upload-bytes counter in the media handler. Dedupe by (community_id, actor_pubkey, object_id) in a subquery so idempotent re-uploads of the same blob are charged once, not once per audit row. Fail safe on malformed historical detail->>'size' values (non-numeric, negative, out-of-range, or exceeding bigint bounds) by validating with a digits-only regex and a lexicographic bound check against i64::MAX, then attributing 0 bytes instead of aborting the whole poller query. The bound check uses ltrim + length comparison and works on all PostgreSQL versions without requiring pg_input_is_valid (PG 16+). Storage aggregation is overflow-safe end to end: the per-user SUM accumulates in numeric (SUM(bigint) returns numeric for wider precision) and is clamped into [0, i64::MAX] before the final cast to bigint, so an extreme historical aggregate degrades to a saturated reading instead of erroring the whole query. Rust-side community/fleet rollups use saturating addition for the same reason — individually valid per-user values can still overflow i64 in aggregate, and these are observability gauges, not a billing ledger. The concurrent index build (migration 0021) is retry-safe via two layers: a startup repair guard drops any indisvalid=false leftover from a failed prior build, and IF NOT EXISTS skips creation when a valid unrecorded index already exists from a bookkeeping race. Both the repair guard and migrator run under a session-scoped advisory lock on a single pinned connection — pg_advisory_lock is session-scoped, so lock/guards/migrator/unlock must all execute on the same PG session; if unlock fails, dropping the connection closes the session and releases the lock automatically. The repair probe is schema-scoped (joins pg_namespace, restricts to current_schema()) so a same-named invalid index in another schema cannot interfere. Named *_objects rather than *_uploads to stay distinct from the new real-time buzz_media_upload_bytes_total event counter added in the media handler. Per-user cardinality (two custom series per community,pubkey pair) is intentional; BUZZ_USAGE_METRICS_PER_COMMUNITY=off remains the emergency kill switch. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>