perf: sync protocol and core hardening updates

This commit is contained in:
A 2026-07-11 19:48:26 +08:00
parent 152fed3b87
commit 4390ebf5a9
283 changed files with 29231 additions and 2295 deletions

View file

@ -208,29 +208,31 @@ INSERT INTO dispatch_outbox (
ON CONFLICT DO NOTHING;
-- name: ClaimDispatchOutbox :many
WITH picked AS (
SELECT d.target_user_id, d.id
FROM dispatch_outbox d
-- durable head 表只保留每用户一行,并同步 head 的 readiness。claim 先锁
-- lane head 再更新对应 outbox 行,既不会扫描 backlog也不会并发领取同一用户。
WITH picked_heads AS (
SELECT h.target_user_id, h.head_id
FROM dispatch_outbox_user_heads h
WHERE (
d.status = 'pending'
AND d.next_attempt_at <= now()
)
OR (
d.status = 'dispatching'
AND d.updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
)
ORDER BY d.next_attempt_at ASC, d.target_user_id ASC, d.pts ASC, d.id ASC
h.status = 'pending'
AND h.next_attempt_at <= now()
)
OR (
h.status = 'dispatching'
AND h.updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
)
ORDER BY h.next_attempt_at ASC, h.target_user_id ASC, h.head_pts ASC, h.head_id ASC
LIMIT sqlc.arg(limit_count)
FOR UPDATE SKIP LOCKED
FOR UPDATE OF h SKIP LOCKED
)
UPDATE dispatch_outbox d
SET
status = 'dispatching',
attempts = d.attempts + 1,
updated_at = now()
FROM picked p
FROM picked_heads p
WHERE d.target_user_id = p.target_user_id
AND d.id = p.id
AND d.id = p.head_id
RETURNING
d.id,
d.target_user_id,
@ -240,25 +242,85 @@ RETURNING
d.exclude_session_id,
d.attempts;
-- name: MarkDispatchDelivered :exec
-- name: ClaimDispatchOutboxShards :many
-- 固定 logical shard 由 target_user_id 决定;运行时 worker 只领取分配给自己的
-- shard 集合,因此同一用户永远只有一条串行 lane而不同用户可并行。
WITH picked_heads AS (
SELECT h.target_user_id, h.head_id
FROM dispatch_outbox_user_heads h
-- 256 与 store.DispatchOutboxLogicalShards、0069 generated column 是同一
-- schema 常量;不得随 worker 数变化。
WHERE h.logical_shard = ANY(sqlc.arg(shard_ids)::smallint[])
AND (
(
h.status = 'pending'
AND h.next_attempt_at <= now()
)
OR (
h.status = 'dispatching'
AND h.updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
)
)
ORDER BY h.next_attempt_at ASC, h.target_user_id ASC, h.head_pts ASC, h.head_id ASC
LIMIT sqlc.arg(limit_count)
FOR UPDATE OF h SKIP LOCKED
)
UPDATE dispatch_outbox d
SET
status = 'dispatching',
attempts = d.attempts + 1,
updated_at = now()
FROM picked_heads p
WHERE d.target_user_id = p.target_user_id
AND d.id = p.head_id
RETURNING
d.id,
d.target_user_id,
d.pts,
d.event_type,
d.exclude_auth_key_id,
d.exclude_session_id,
d.attempts;
-- name: MarkDispatchDelivered :execrows
-- 方案 A投递成功即删除。outbox 是任务队列delivered 行无保留价值
-- (消息在 message_boxes、离线补偿在 user_update_events删除让表维持「未完成任务」小稳态。
DELETE FROM dispatch_outbox
WHERE target_user_id = $1
AND id = $2;
-- claim 的锁序是 user_heads→outboxcompletion 必须先显式锁同一 head 再删 outbox
-- 否则租约过期 claim 与完成恰好竞争时会形成 outbox→head / head→outbox 环路。
WITH locked_head AS MATERIALIZED (
SELECT h.target_user_id
FROM dispatch_outbox_user_heads h
WHERE h.target_user_id = sqlc.arg(target_user_id)::bigint
FOR UPDATE
)
DELETE FROM dispatch_outbox d
USING locked_head h
WHERE d.target_user_id = h.target_user_id
AND d.id = sqlc.arg(id)::bigint
AND d.status = 'dispatching'
AND d.attempts = sqlc.arg(expected_attempts)::int;
-- name: MarkDispatchFailed :exec
UPDATE dispatch_outbox
-- name: MarkDispatchFailed :execrows
WITH locked_head AS MATERIALIZED (
SELECT h.target_user_id
FROM dispatch_outbox_user_heads h
WHERE h.target_user_id = sqlc.arg(target_user_id)::bigint
FOR UPDATE
)
UPDATE dispatch_outbox d
SET
status = CASE WHEN attempts >= 5 THEN 'failed' ELSE 'pending' END,
status = CASE WHEN d.attempts >= 5 THEN 'failed' ELSE 'pending' END,
next_attempt_at = CASE
WHEN attempts >= 5 THEN next_attempt_at
ELSE now() + make_interval(secs => LEAST(60, attempts * attempts))
WHEN d.attempts >= 5 THEN d.next_attempt_at
ELSE now() + make_interval(secs => LEAST(60, d.attempts * d.attempts))
END,
last_error = $3,
last_error = sqlc.arg(last_error)::text,
updated_at = now()
WHERE target_user_id = $1
AND id = $2;
FROM locked_head h
WHERE d.target_user_id = h.target_user_id
AND d.id = sqlc.arg(id)::bigint
AND d.status = 'dispatching'
AND d.attempts = sqlc.arg(expected_attempts)::int;
-- name: BatchListDispatchEvents :many
-- 按 (user_id, pts) 精确批量取账号事件,供 outbox worker 一次性加载一批 claim 的事件详情,
@ -394,22 +456,44 @@ LEFT JOIN users from_u ON from_u.id = m.from_user_id
LEFT JOIN users fwd_u ON m.fwd_from_peer_type = 'user' AND fwd_u.id = m.fwd_from_peer_id
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id;
-- name: MarkDispatchDeliveredBatch :exec
-- name: MarkDispatchDeliveredBatch :execrows
-- 批量删除一批已投递的 (target_user_id, id)target_user_id 入 WHERE 命中唯一索引并避免串删。
WITH input AS MATERIALIZED (
SELECT tu.target_user_id, di.id, ea.attempts
FROM unnest(@target_user_ids::bigint[]) WITH ORDINALITY AS tu(target_user_id, ord)
JOIN unnest(@ids::bigint[]) WITH ORDINALITY AS di(id, ord) USING (ord)
JOIN unnest(@expected_attempts::int[]) WITH ORDINALITY AS ea(attempts, ord) USING (ord)
),
locked_heads AS MATERIALIZED (
SELECT h.target_user_id
FROM dispatch_outbox_user_heads h
JOIN (SELECT DISTINCT target_user_id FROM input) i USING (target_user_id)
-- Match ClaimDispatchOutbox[Shards] exactly. A stale-lease claim may lock several
-- dispatching heads while this completion batch locks the same set; a different
-- multi-row order would merely move the deadlock one level up.
ORDER BY h.next_attempt_at, h.target_user_id, h.head_pts, h.head_id
FOR UPDATE OF h
)
DELETE FROM dispatch_outbox d
USING unnest(@target_user_ids::bigint[]) WITH ORDINALITY AS tu(target_user_id, ord)
JOIN unnest(@ids::bigint[]) WITH ORDINALITY AS di(id, ord) USING (ord)
WHERE d.target_user_id = tu.target_user_id
AND d.id = di.id;
USING input i, locked_heads h
WHERE d.target_user_id = h.target_user_id
AND d.target_user_id = i.target_user_id
AND d.id = i.id
AND d.status = 'dispatching'
AND d.attempts = i.attempts;
-- name: DeleteFailedDispatchOutbox :one
WITH doomed AS (
SELECT target_user_id, id
FROM dispatch_outbox
WHERE status = 'failed'
AND updated_at < now() - make_interval(secs => sqlc.arg(older_than_seconds)::int)
ORDER BY updated_at ASC, target_user_id ASC, id ASC
-- failed 只能成为 lane head从 head 表开始并先锁 head既走 0074 的小索引,也与
-- claim/completion 保持同一 user_heads→outbox 锁序。删除的只是在线任务durable
-- user_update_events 不动,故客户端仍可经 difference 恢复。
WITH doomed AS MATERIALIZED (
SELECT h.target_user_id, h.head_id AS id
FROM dispatch_outbox_user_heads h
WHERE h.status = 'failed'
AND h.updated_at < now() - make_interval(secs => sqlc.arg(older_than_seconds)::int)
ORDER BY h.updated_at ASC, h.target_user_id ASC, h.head_id ASC
LIMIT sqlc.arg(limit_count)
FOR UPDATE OF h SKIP LOCKED
),
deleted AS (
DELETE FROM dispatch_outbox d