mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
feat(relay): deliver pubkey mentions to relay companions (#7793)
We are introducing a companion service to the relay that needs pubkey event mentions for pubkeys it manages. This PR introduces an outbox for pubkey mentions that will be sent to these "operator listener" services. ## Summary Deliver mentions of registered pubkeys to deployment-global operator listeners. - Configure listeners with `BUZZ_OPERATOR_LISTENERS`; listeners manage target pubkeys through NIP-98-authenticated `POST`/`DELETE /operator/listener/pubkeys` requests. - During supported event ingestion, match `p` tags to registrations and insert one outbox row per listener in the event transaction. - A background worker claims up to 10 rows, sends NIP-98-signed notifications, and retries transient failures with exponential backoff for up to 9 attempts (idle polling backs off from 250 ms to 2 s). - Outbox rows are ineligible for delivery after 15 minutes and are reaped every 5 minutes. Registered pubkeys live for 30 days; re-registering renews them, and a daily reaper removes expired registrations. - Keep persistence app-managed: no database triggers, functions, foreign keys, or separate match queue. ## Changed behavior Listener outbox rows are enqueued inside the shared event-insert and thread-metadata transactions; enqueue failure rolls back the event. `event_mentions` behavior is unchanged: ordinary event/reaction mention indexing remains post-commit best effort with warning-only failures. ## Testing - `cargo fmt --all` - `cargo test -p buzz-db --lib` - `cargo test -p buzz-relay --lib config::tests::operator_listener_routes` - `cargo check -p buzz-db -p buzz-relay`
This commit is contained in:
@@ -1494,7 +1494,7 @@ LANGUAGE SQL IMMUTABLE STRICT PARALLEL SAFE AS $$
|
||||
'community_deletion_requests', 'community_deletion_approvals',
|
||||
'community_deletion_checkpoints', 'community_serving_write_leases',
|
||||
'community_deletion_executor_heartbeats', 'product_feedback',
|
||||
'rate_limit_violations'
|
||||
'rate_limit_violations', 'operator_listener_outbox'
|
||||
]::TEXT[])
|
||||
$$;
|
||||
|
||||
@@ -1878,6 +1878,51 @@ CREATE INDEX idx_relay_admin_outbox_pending
|
||||
INSERT INTO _operator_global_tables (table_name, reason) VALUES
|
||||
('relay_admin_outbox', 'deployment-global enforcement artifact delivery queue');
|
||||
|
||||
-- ── Operator-listener mention delivery ──────────────────────────────────────
|
||||
-- Listener registrations are deployment-global. The outbox records community
|
||||
-- provenance for the event, but is intentionally not tenant-owned.
|
||||
|
||||
CREATE TABLE operator_listener_pubkeys (
|
||||
listener_pubkey BYTEA NOT NULL CHECK (length(listener_pubkey) = 32),
|
||||
target_pubkey BYTEA NOT NULL CHECK (length(target_pubkey) = 32),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (listener_pubkey, target_pubkey)
|
||||
);
|
||||
CREATE INDEX operator_listener_pubkeys_target
|
||||
ON operator_listener_pubkeys (target_pubkey, listener_pubkey);
|
||||
CREATE INDEX operator_listener_pubkeys_created_at
|
||||
ON operator_listener_pubkeys (created_at);
|
||||
|
||||
CREATE TABLE operator_listener_outbox (
|
||||
id UUID NOT NULL PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
listener_pubkey BYTEA NOT NULL CHECK (length(listener_pubkey) = 32),
|
||||
target_pubkey BYTEA NOT NULL CHECK (length(target_pubkey) = 32),
|
||||
community_id UUID NOT NULL,
|
||||
event_id BYTEA NOT NULL CHECK (length(event_id) = 32),
|
||||
event_kind INTEGER NOT NULL,
|
||||
event_created_at TIMESTAMPTZ NOT NULL,
|
||||
state TEXT NOT NULL DEFAULT 'pending'
|
||||
CHECK (state IN ('pending', 'sending')),
|
||||
attempts INTEGER NOT NULL DEFAULT 0 CHECK (attempts >= 0),
|
||||
next_attempt_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
lease_until TIMESTAMPTZ,
|
||||
claim_id UUID,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (listener_pubkey, target_pubkey, community_id, event_id)
|
||||
);
|
||||
CREATE INDEX operator_listener_outbox_due
|
||||
ON operator_listener_outbox (next_attempt_at, created_at, id)
|
||||
WHERE state = 'pending';
|
||||
CREATE INDEX operator_listener_outbox_recovery
|
||||
ON operator_listener_outbox (lease_until, created_at, id)
|
||||
WHERE state = 'sending';
|
||||
CREATE INDEX operator_listener_outbox_created_at
|
||||
ON operator_listener_outbox (created_at);
|
||||
|
||||
INSERT INTO _operator_global_tables (table_name, reason) VALUES
|
||||
('operator_listener_pubkeys', 'deployment-global target registrations for operator listeners'),
|
||||
('operator_listener_outbox', 'deployment-global mention delivery queue; community_id is event provenance');
|
||||
|
||||
-- ── Relay operator audit (append-only roster mutation trail) ─────────────────
|
||||
-- One row per PUT/DELETE /operators/{pubkey} mutation. The roster is the
|
||||
-- deployment-wide root of trust and its mutations overwrite/remove in place;
|
||||
|
||||
Reference in New Issue
Block a user