chore: build
Backend - Build & Lint / build (push) Failing after 32m27s

This commit is contained in:
Xor290
2026-08-08 00:27:56 +02:00
parent 5c84dfed66
commit c6830873ba
3 changed files with 22 additions and 59 deletions
+22 -7
View File
@@ -5,6 +5,8 @@ import (
"gestion/models" "gestion/models"
"log" "log"
"time" "time"
"gorm.io/gorm"
) )
// CreateProduct crée un nouveau produit avec ses prix // CreateProduct crée un nouveau produit avec ses prix
@@ -262,14 +264,27 @@ func (d *Database) UpdateProduct(productID int, name, category, description, uni
return nil return nil
} }
// SetProductStock fixe le stock à une valeur absolue. Le verrou FOR UPDATE
// sérialise cette écriture avec les décréments du checkout (db_commands.go) :
// sans lui, une modification admin pourrait écraser silencieusement le
// décrément d'une commande passée au même instant sur le même produit.
func (d *Database) SetProductStock(productID int, stock float64) error { func (d *Database) SetProductStock(productID int, stock float64) error {
result := d.GDB.Exec(`UPDATE products SET stock = ?, updated_at = ? WHERE id = ?`, err := d.GDB.Transaction(func(tx *gorm.DB) error {
stock, time.Now(), productID) var exists int
if result.Error != nil { if err := tx.Raw(`SELECT 1 FROM products WHERE id = ? FOR UPDATE`, productID).Scan(&exists).Error; err != nil {
return fmt.Errorf("erreur mise à jour stock: %w", result.Error) return fmt.Errorf("erreur verrouillage produit: %w", err)
} }
if result.RowsAffected == 0 { if exists == 0 {
return fmt.Errorf("produit non trouvé") return fmt.Errorf("produit non trouvé")
}
if err := tx.Exec(`UPDATE products SET stock = ?, updated_at = ? WHERE id = ?`,
stock, time.Now(), productID).Error; err != nil {
return fmt.Errorf("erreur mise à jour stock: %w", err)
}
return nil
})
if err != nil {
return err
} }
return nil return nil
} }
-8
View File
@@ -19,11 +19,3 @@ type DeliveryPersonStatus struct {
CurrentCommand int `json:"current_command,omitempty"` CurrentCommand int `json:"current_command,omitempty"`
LastUpdate time.Time `json:"last_update"` LastUpdate time.Time `json:"last_update"`
} }
type StockReservation struct {
ProductID int `json:"product_id"`
Quantity int `json:"quantity"`
Username string `json:"username"`
ExpiresAt time.Time `json:"expires_at"`
CommandID int `json:"command_id"`
}
-44
View File
@@ -17,8 +17,6 @@ func StartRedisWorkers(database *db.Database) {
go AutoAssignWorker(database) go AutoAssignWorker(database)
go StockCleanupWorker(database)
go PointsSyncWorker(database) go PointsSyncWorker(database)
log.Println("✅ Tous les workers Redis sont démarrés") log.Println("✅ Tous les workers Redis sont démarrés")
@@ -76,48 +74,6 @@ func AutoAssignWorker(database *db.Database) {
} }
} }
// ============================================
// WORKER NETTOYAGE STOCK
// ============================================
// StockCleanupWorker nettoie les réservations expirées
func StockCleanupWorker(database *db.Database) {
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
log.Println("🧹 Worker Nettoyage Stock démarré (check toutes les 5 min)")
for range ticker.C {
cleanedCount := 0
// Récupérer toutes les clés de réservation
keys, err := db.Redis.Keys(db.RedisCtx, "stock:reserve:*").Result()
if err != nil {
log.Printf("⚠️ Erreur récupération réservations: %v", err)
continue
}
for _, key := range keys {
// Vérifier si la réservation est expirée
ttl, err := db.Redis.TTL(db.RedisCtx, key).Result()
if err != nil {
continue
}
// Si TTL <= 0, la réservation est expirée
if ttl <= 0 {
// Redis va automatiquement supprimer la clé
// Mais on peut log pour traçabilité
cleanedCount++
}
}
if cleanedCount > 0 {
log.Printf("🧹 %d réservations de stock expirées nettoyées", cleanedCount)
}
}
}
// ============================================ // ============================================
// WORKER SYNCHRONISATION POINTS // WORKER SYNCHRONISATION POINTS
// ============================================ // ============================================