From b30b450b21dbdb4b759d87db897b710de2a4b537 Mon Sep 17 00:00:00 2001 From: MrMissx Date: Sat, 10 Feb 2024 08:26:11 +0700 Subject: [PATCH] fix(document): race condition on view increment --- model/document.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/model/document.go b/model/document.go index 469888d..d794155 100644 --- a/model/document.go +++ b/model/document.go @@ -17,6 +17,7 @@ type Document struct { func insertDocument(db *sqlx.DB, doc *Document, retry int) error { if retry > 3 { + utils.Logger.Warning("Failed to insert document after 3 retries") return nil } @@ -33,6 +34,7 @@ func insertDocument(db *sqlx.DB, doc *Document, retry int) error { pgErr, ok := err.(*pq.Error) // duplicate slug if ok && pgErr.Code == "23505" && retry <= 3 { + utils.Logger.Warning("Slug %s already exists, retrying...", doc.Slug) return insertDocument(db, doc, retry+1) } } @@ -45,10 +47,18 @@ func (doc *Document) Create(db *sqlx.DB) error { } func (doc *Document) incrementViews(db *sqlx.DB) { - _, err := db.Exec("UPDATE documents SET views = views + 1 WHERE slug = $1", doc.Slug) - if err != nil { - utils.Logger.Error("Failed to update document '%v' : %v", doc.Slug, err) - } + tx, err := db.Beginx() + + defer func() { + if err != nil { + tx.Rollback() + utils.Logger.Error("Failed to start transaction: %v", err) + } else { + tx.Commit() + } + }() + + _, err = tx.Exec("UPDATE documents SET views = views + 1 WHERE slug = $1", doc.Slug) } func (doc *Document) GetBySlug(db *sqlx.DB, slug string) error {