Implement retry logic for UpdateAttributes

This commit is contained in:
Jason Streifling 2024-03-15 15:18:02 +01:00
parent 3d3fb3c826
commit 6d3a28a6ce
3 changed files with 40 additions and 24 deletions

View File

@ -20,8 +20,7 @@ func (db *DB) AddArticle(a *Article) (int64, error) {
query := ` query := `
INSERT INTO articles INSERT INTO articles
(title, description, content, published, rejected, author_id) (title, description, content, published, rejected, author_id)
VALUES VALUES (?, ?, ?, ?, ?, ?)
(?, ?, ?, ?, ?, ?)
` `
result, err := db.Exec(query, a.Title, a.Description, a.Content, a.Published, result, err := db.Exec(query, a.Title, a.Description, a.Content, a.Published,

View File

@ -5,14 +5,19 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"log" "log"
"math"
"math/rand/v2"
"os" "os"
"strings" "strings"
"syscall" "syscall"
"time"
"github.com/go-sql-driver/mysql" "github.com/go-sql-driver/mysql"
"golang.org/x/term" "golang.org/x/term"
) )
var TxMaxRetries = 3
type DB struct { type DB struct {
*sql.DB *sql.DB
} }
@ -92,29 +97,42 @@ func OpenDB(dbName string) (*DB, error) {
} }
func (db *DB) UpdateAttributes(a ...*Attribute) error { func (db *DB) UpdateAttributes(a ...*Attribute) error {
tx, err := db.Begin() for i := 0; i < TxMaxRetries; i++ {
if err != nil { err := func() error {
return fmt.Errorf("error starting transaction: %v", err) tx, err := db.Begin()
} if err != nil {
return fmt.Errorf("error starting transaction: %v", err)
for _, attribute := range a {
query := fmt.Sprintf(`
UPDATE %s
SET %s = ?
WHERE id = ?
`, attribute.Table, attribute.AttName)
if _, err := tx.Exec(query, attribute.Value, attribute.ID); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("error: transaction error: %v, rollback error: %v", err, rollbackErr)
} }
return fmt.Errorf("error updating %v in DB: %v", attribute.AttName, err)
}
}
if err = tx.Commit(); err != nil { for _, attribute := range a {
return fmt.Errorf("error committing transaction: %v", err) query := fmt.Sprintf(`
UPDATE %s
SET %s = ?
WHERE id = ?
`, attribute.Table, attribute.AttName)
if _, err := tx.Exec(query, attribute.Value, attribute.ID); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("error: transaction error: %v, rollback error: %v", err, rollbackErr)
}
return fmt.Errorf("error updating %v in DB: %v", attribute.AttName, err)
}
}
if err = tx.Commit(); err != nil {
return fmt.Errorf("error committing transaction: %v", err)
}
return nil
}()
if err == nil {
return nil
}
log.Println(err)
waitTime := time.Duration(math.Pow(2, float64(i))) * time.Second
jitter := time.Duration(rand.IntN(1000)) * time.Millisecond
time.Sleep(waitTime + jitter)
} }
return nil return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
} }
func (db *DB) CountEntries(table string) (int64, error) { func (db *DB) CountEntries(table string) (int64, error) {

View File

@ -28,8 +28,7 @@ func (db *DB) AddUser(user *User, pass string) error {
} }
query := ` query := `
INSERT INTO users INSERT INTO users (username, password, first_name, last_name, role)
(username, password, first_name, last_name, role)
VALUES (?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?)
` `
if _, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role); err != nil { if _, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role); err != nil {