fix(submit): 待审上限在事务内加咨询锁原子检查,跨副本不超额

This commit is contained in:
Lemon-miaow committed 2026-09-24 22:26:30 +08:00
1 parent a27d76ae1d
commit 5cadbd40a9
5 files changed
+114 -40

No files matched your search

+26 -4
View File
@@ -24,13 +24,35 @@ var _ Store = (*PGStore)(nil)
const submissionColumns = `id, submitted_by, display_name, context_ref, status,
image_ref, build_id, reviewed_by, reject_reason, created_at, reviewed_at, context_sha256`
func (s *PGStore) CreateSubmission(ctx context.Context, sub *Submission) error {
// CreateSubmission counts and inserts in one transaction under a per-submitter
// advisory lock, so two creates by the same user, on one replica or several,
// serialize and the second sees the first's row. A hashtext collision between
// two users only serializes their creates.
func (s *PGStore) CreateSubmission(ctx context.Context, sub *Submission, maxPending int) (int, error) {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return 0, err
}
defer func() { _ = tx.Rollback() }()
if _, err := tx.ExecContext(ctx, `SELECT pg_advisory_xact_lock(hashtext('submission:' || $1))`, sub.SubmittedBy); err != nil {
return 0, err
}
var pending int
if err := tx.QueryRowContext(ctx, `SELECT count(*) FROM image_submissions
WHERE submitted_by = $1 AND status = 'pending_review'`, sub.SubmittedBy).Scan(&pending); err != nil {
return 0, err
}
if pending >= maxPending {
return pending, ErrQuotaExceeded
}
const q = `INSERT INTO image_submissions
(id, submitted_by, display_name, context_ref, status, created_at)
VALUES ($1, $2, $3, $4, $5, $6)`
_, err := s.db.ExecContext(ctx, q,
sub.ID, sub.SubmittedBy, sub.DisplayName, sub.ContextRef, string(sub.Status), sub.CreatedAt)
return err
if _, err := tx.ExecContext(ctx, q,
sub.ID, sub.SubmittedBy, sub.DisplayName, sub.ContextRef, string(sub.Status), sub.CreatedAt); err != nil {
return pending, err
}
return pending, tx.Commit()
}
func (s *PGStore) CountPendingSubmissionsBy(ctx context.Context, submittedBy string) (int, error) {