Files
projet_gestion_commande/backend/gestion/db/redis_deliveryman_assignment.go
T
2026-03-27 22:23:46 +01:00

171 lines
4.4 KiB
Go

package db
import (
"encoding/json"
"fmt"
"gestion/models"
"log"
"math"
)
// FindLeastLoadedDeliveryman trouve le livreur avec le moins de commandes ET qui peut accepter
func (d *Database) FindLeastLoadedDeliveryman() (string, error) {
keys, err := Redis.Keys(RedisCtx, "delivery:status:*").Result()
if err != nil || len(keys) == 0 {
return "", fmt.Errorf("aucun livreur trouvé")
}
var leastLoaded string
minQueueSize := int64(MAX_COMMANDS_PER_DELIVERYMAN + 1)
for _, key := range keys {
username := key[len("delivery:status:"):]
data, err := Redis.Get(RedisCtx, key).Result()
if err != nil {
continue
}
var status models.DeliveryPersonStatus
json.Unmarshal([]byte(data), &status)
if status.Status == "offline" {
continue
}
// ✅ NOUVEAU: Vérifier si le livreur peut accepter des commandes
if !d.CanDeliverymanAcceptCommands(username) {
log.Printf("⏭️ [LEAST_LOADED] Skip %s: ne peut pas accepter", username)
continue
}
queueKey := fmt.Sprintf("queue:deliveryman:%s", username)
queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
// Priorité aux livreurs disponibles (bonus de -1000)
effectiveQueueSize := queueSize
if status.Status == "available" {
effectiveQueueSize -= 1000
}
if effectiveQueueSize < minQueueSize {
minQueueSize = effectiveQueueSize
leastLoaded = username
}
}
if leastLoaded == "" {
return "", fmt.Errorf("aucun livreur disponible")
}
queueKey := fmt.Sprintf("queue:deliveryman:%s", leastLoaded)
actualQueueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
log.Printf("🎯 [LEAST_LOADED] %s sélectionné (%d/10 commandes)",
leastLoaded, actualQueueSize)
return leastLoaded, nil
}
// FindAvailableOrLeastLoadedDeliveryman trouve un livreur disponible ou le moins chargé
func (d *Database) FindAvailableOrLeastLoadedDeliveryman() (string, string, int, error) {
keys, err := Redis.Keys(RedisCtx, "delivery:status:*").Result()
if err != nil || len(keys) == 0 {
return "", "", 0, fmt.Errorf("aucun livreur trouvé")
}
var bestDeliveryman string
var bestStatus string
bestQueueSize := int64(MAX_COMMANDS_PER_DELIVERYMAN + 1)
for _, key := range keys {
username := key[len("delivery:status:"):]
data, err := Redis.Get(RedisCtx, key).Result()
if err != nil {
continue
}
var status models.DeliveryPersonStatus
json.Unmarshal([]byte(data), &status)
if status.Status == "offline" {
continue
}
if !d.CanDeliverymanAcceptCommands(username) {
continue
}
queueKey := fmt.Sprintf("queue:deliveryman:%s", username)
queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
if status.Status == "available" && queueSize == 0 {
return username, "available", 0, nil
}
if queueSize < bestQueueSize {
bestQueueSize = queueSize
bestDeliveryman = username
bestStatus = status.Status
}
}
if bestDeliveryman == "" {
return "", "", 0, fmt.Errorf("tous les livreurs sont au maximum de leur capacité")
}
return bestDeliveryman, bestStatus, int(bestQueueSize), nil
}
// GetLeastLoadedDeliverymanForced retourne le livreur avec le moins de commandes (SANS limite)
func (d *Database) GetLeastLoadedDeliverymanForced() (string, int64, error) {
activeUsernames, err := d.GetAllActiveDeliverymenUsernames()
if err != nil || len(activeUsernames) == 0 {
return "", 0, fmt.Errorf("aucun livreur actif")
}
var leastLoaded string
var minQueueSize int64 = math.MaxInt64
for _, username := range activeUsernames {
queueKey := fmt.Sprintf("queue:deliveryman:%s", username)
queueSize, _ := Redis.ZCard(RedisCtx, queueKey).Result()
if queueSize < minQueueSize {
minQueueSize = queueSize
leastLoaded = username
}
}
return leastLoaded, minQueueSize, nil
}
// AreAllDeliverymenAtCapacity vérifie si tous les livreurs ont atteint leur capacité max
func (d *Database) AreAllDeliverymenAtCapacity() (bool, int, error) {
activeUsernames, err := d.GetAllActiveDeliverymenUsernames()
if err != nil || len(activeUsernames) == 0 {
return false, 0, fmt.Errorf("aucun livreur actif")
}
if len(activeUsernames) == 1 {
return false, 1, nil
}
atCapacityCount := 0
for _, username := range activeUsernames {
if !d.CanDeliverymanAcceptCommands(username) {
atCapacityCount++
}
}
allAtCapacity := atCapacityCount == len(activeUsernames)
if allAtCapacity {
log.Printf("🔴 [CAPACITY] TOUS les livreurs sont à capacité maximale (%d/%d)",
atCapacityCount, len(activeUsernames))
}
return allAtCapacity, len(activeUsernames), nil
}