perf(worker): 公平调度跨节点异步准入锁
持续突发提交会通过 pg_try_advisory_xact_lock 反复抢占全局容量锁,使 Worker 补槽器在首批之后饥饿。\n\n跨进程锁改为 PostgreSQL 公平等待;进程内锁仍保证每个 API 或 Worker 最多一条连接参与等待,30 秒 lock_timeout 会回到原有重试路径,60 秒空闲事务超时继续处理失主会话。\n\n验证:临时 PostgreSQL 18 上 64 并发锁竞争峰值连接不超过 2;Go 全量测试、go vet、gofmt 通过。
This commit is contained in:
@@ -115,18 +115,21 @@ func admissionOperationLockKeys(input TaskAdmissionInput) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tryAdmissionTransactionLock(ctx context.Context, tx pgx.Tx, key string) error {
|
func tryAdmissionTransactionLock(ctx context.Context, tx pgx.Tx, key string) error {
|
||||||
var locked bool
|
// The process-local lock limits this wait to one PostgreSQL connection per
|
||||||
if err := tx.QueryRow(
|
// API or Worker process. Let PostgreSQL queue those process representatives
|
||||||
|
// fairly: repeated pg_try_advisory_xact_lock calls let a sustained submit
|
||||||
|
// burst starve the Worker dispatcher that must release queue pressure.
|
||||||
|
// lock_timeout bounds a lost-owner wait and converts it back into the
|
||||||
|
// existing transaction retry path.
|
||||||
|
_, err := tx.Exec(
|
||||||
ctx,
|
ctx,
|
||||||
`SELECT pg_try_advisory_xact_lock(hashtextextended($1, 0))`,
|
`SELECT pg_advisory_xact_lock(hashtextextended($1, 0))`,
|
||||||
key,
|
key,
|
||||||
).Scan(&locked); err != nil {
|
)
|
||||||
return err
|
if IsPostgresLockTimeout(err) {
|
||||||
}
|
|
||||||
if !locked {
|
|
||||||
return errAdmissionLockBusy
|
return errAdmissionLockBusy
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func retryAdmissionOperation[T any](
|
func retryAdmissionOperation[T any](
|
||||||
|
|||||||
Reference in New Issue
Block a user