diff --git a/backend/gestion/db/db_notifications.go b/backend/gestion/db/db_notifications.go index 148aff17..fef89dde 100644 --- a/backend/gestion/db/db_notifications.go +++ b/backend/gestion/db/db_notifications.go @@ -33,8 +33,11 @@ func (d *Database) NotifyClient(username string, commandID int, notifType, messa } notifJSON, _ := json.Marshal(notification) - Redis.LPush(RedisCtx, notifKey, notifJSON) - Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe := Redis.Pipeline() + pipe.LPush(RedisCtx, notifKey, notifJSON) + pipe.LTrim(RedisCtx, notifKey, 0, 199) + pipe.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe.Exec(RedisCtx) //nolint if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { if chatID, ok, err := d.GetClientTelegramChatID(username); err == nil && ok { @@ -64,8 +67,11 @@ func (d *Database) NotifyLivreur(username string, commandID int, notifType, mess } notifJSON, _ := json.Marshal(notification) - Redis.LPush(RedisCtx, notifKey, notifJSON) - Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe2 := Redis.Pipeline() + pipe2.LPush(RedisCtx, notifKey, notifJSON) + pipe2.LTrim(RedisCtx, notifKey, 0, 199) + pipe2.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe2.Exec(RedisCtx) //nolint if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { if chatID, ok, err := d.GetUserTelegramChatID(username); err == nil && ok { @@ -103,19 +109,23 @@ func (d *Database) NotifyAllAdminCabine(commandID int, clientUsername, deliveryA } notifJSON, _ := json.Marshal(notification) - count := 0 + pipe := Redis.Pipeline() for _, u := range users { notifKey := fmt.Sprintf("notifications:%s", u.Username) - Redis.LPush(RedisCtx, notifKey, notifJSON) - Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe.LPush(RedisCtx, notifKey, notifJSON) + pipe.LTrim(RedisCtx, notifKey, 0, 199) + pipe.Expire(RedisCtx, notifKey, 7*24*time.Hour) + } + pipe.Exec(RedisCtx) //nolint - if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { + count := len(users) + if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { + for _, u := range users { if chatID, ok, err := d.GetUserTelegramChatID(u.Username); err == nil && ok { capturedChatID := chatID go sendTelegramNotif(capturedChatID, fmt.Sprintf("🔔 Nouvelle commande\n\n%s", msg)) } } - count++ } log.Printf("📬 [ADMIN_NOTIF] Notif Redis (%d users) pour commande #%d", count, commandID) } @@ -141,19 +151,23 @@ func (d *Database) NotifyAllAdminCabineAlert(alertID int, livreurUsername, alert } notifJSON, _ := json.Marshal(notification) - count := 0 + pipe := Redis.Pipeline() for _, u := range users { notifKey := fmt.Sprintf("notifications:%s", u.Username) - Redis.LPush(RedisCtx, notifKey, notifJSON) - Redis.Expire(RedisCtx, notifKey, 7*24*time.Hour) + pipe.LPush(RedisCtx, notifKey, notifJSON) + pipe.LTrim(RedisCtx, notifKey, 0, 199) + pipe.Expire(RedisCtx, notifKey, 7*24*time.Hour) + } + pipe.Exec(RedisCtx) //nolint - if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { + count := len(users) + if services.TelegramBot != nil && services.TelegramBot.IsNotificationsEnabled() { + for _, u := range users { if chatID, ok, err := d.GetUserTelegramChatID(u.Username); err == nil && ok { capturedChatID := chatID go sendTelegramNotif(capturedChatID, fmt.Sprintf("🚨 Alerte livreur\n\n%s", body)) } } - count++ } log.Printf("🚨 [ALERT_NOTIF] Notif Redis (%d users) pour alerte #%d de %s", count, alertID, livreurUsername) } diff --git a/backend/gestion/db/redis_queue_clean_up.go b/backend/gestion/db/redis_queue_clean_up.go index 9b5fb81f..36904a35 100644 --- a/backend/gestion/db/redis_queue_clean_up.go +++ b/backend/gestion/db/redis_queue_clean_up.go @@ -13,7 +13,7 @@ import ( func (d *Database) CleanupInvalidQueueCommands() (int, error) { log.Println("🧹 [CLEANUP] Démarrage du nettoyage des commandes invalides...") - keys, err := Redis.Keys(RedisCtx, "queue:pending:*").Result() + keys, err := scanRedisKeys("queue:pending:*") if err != nil { return 0, fmt.Errorf("erreur récupération des clés: %w", err) } @@ -94,7 +94,7 @@ func (d *Database) removeInvalidCommand(key string, commandID int, reason string Redis.ZRem(RedisCtx, "queue:priority:sorted", commandIDStr) // 3. Supprimer des queues de livreurs - livreurKeys, _ := Redis.Keys(RedisCtx, "queue:deliveryman:*").Result() + livreurKeys, _ := scanRedisKeys("queue:deliveryman:*") for _, queueKey := range livreurKeys { if len(queueKey) > 6 && queueKey[len(queueKey)-6:] == ":count" { continue diff --git a/backend/gestion/db/redis_queue_info.go b/backend/gestion/db/redis_queue_info.go index 5a27b350..7a518981 100644 --- a/backend/gestion/db/redis_queue_info.go +++ b/backend/gestion/db/redis_queue_info.go @@ -68,8 +68,9 @@ func (d *Database) GetAllQueuesOverview() (map[string]any, error) { overview["general_queue"] = generalQueueSize deliverymanQueues := make(map[string]any) - keys, _ := Redis.Keys(RedisCtx, "queue:deliveryman:*").Result() + keys, _ := scanRedisKeys("queue:deliveryman:*") + var totalPending int64 = generalQueueSize for _, key := range keys { if len(key) > 6 && key[len(key)-6:] == ":count" { continue @@ -83,16 +84,7 @@ func (d *Database) GetAllQueuesOverview() (map[string]any, error) { "can_accept_more": queueSize < MAX_COMMANDS_PER_DELIVERYMAN, "capacity": fmt.Sprintf("%d/%d", queueSize, MAX_COMMANDS_PER_DELIVERYMAN), } - } - - overview["deliveryman_queues"] = deliverymanQueues - var totalPending int64 = generalQueueSize - for _, key := range keys { - if len(key) > 6 && key[len(key)-6:] == ":count" { - continue - } - size, _ := Redis.ZCard(RedisCtx, key).Result() - totalPending += size + totalPending += queueSize } overview["total_pending"] = totalPending @@ -105,7 +97,7 @@ func (d *Database) GetQueueStats() (map[string]any, error) { priorityCount, _ := Redis.ZCard(RedisCtx, "queue:priority:sorted").Result() var deliverymanQueueCount int64 - keys, _ := Redis.Keys(RedisCtx, "queue:deliveryman:*").Result() + keys, _ := scanRedisKeys("queue:deliveryman:*") for _, key := range keys { if len(key) > 6 && key[len(key)-6:] == ":count" { continue @@ -117,7 +109,8 @@ func (d *Database) GetQueueStats() (map[string]any, error) { var totalWaitTime int64 var commandCount int64 - normalResults, _ := Redis.ZRangeWithScores(RedisCtx, "queue:pending:sorted", 0, -1).Result() + // Limité aux 100 premières entrées pour ne pas bloquer Redis sur une grande queue + normalResults, _ := Redis.ZRangeWithScores(RedisCtx, "queue:pending:sorted", 0, 99).Result() for _, result := range normalResults { commandID := extractCommandID(result.Member) if commandID <= 0 { diff --git a/backend/gestion/db/redis_queue_management.go b/backend/gestion/db/redis_queue_management.go index ae5097ce..4d46d060 100644 --- a/backend/gestion/db/redis_queue_management.go +++ b/backend/gestion/db/redis_queue_management.go @@ -153,7 +153,7 @@ func (d *Database) RemoveCommandFromQueue(commandID int) error { pipe.ZRem(RedisCtx, "queue:priority:sorted", commandIDStr) // Trouver et retirer de la queue du livreur - keys, _ := Redis.Keys(RedisCtx, "queue:deliveryman:*").Result() + keys, _ := scanRedisKeys("queue:deliveryman:*") var affectedDeliveryman string for _, queueKey := range keys { @@ -303,7 +303,7 @@ func (d *Database) SyncAllDeliverymanStatuses() error { // iterDeliveryStatuses itère sur tous les statuts Redis des livreurs et appelle fn pour chacun. func (d *Database) iterDeliveryStatuses(fn func(models.DeliveryPersonStatus)) error { - keys, err := Redis.Keys(RedisCtx, "delivery:status:*").Result() + keys, err := scanRedisKeys("delivery:status:*") if err != nil { return err } @@ -320,3 +320,21 @@ func (d *Database) iterDeliveryStatuses(fn func(models.DeliveryPersonStatus)) er } return nil } + +// scanRedisKeys remplace KEYS * par SCAN pour ne pas bloquer Redis. +func scanRedisKeys(pattern string) ([]string, error) { + var all []string + cursor := uint64(0) + for { + batch, next, err := Redis.Scan(RedisCtx, cursor, pattern, 200).Result() + if err != nil { + return nil, err + } + all = append(all, batch...) + cursor = next + if cursor == 0 { + break + } + } + return all, nil +} diff --git a/backend/gestion/handlers/auth.go b/backend/gestion/handlers/auth.go index ff51915e..03eee1fc 100644 --- a/backend/gestion/handlers/auth.go +++ b/backend/gestion/handlers/auth.go @@ -838,6 +838,14 @@ func CreateUser(c *gin.Context) { return } + hashed, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost) + if err != nil { + log.Printf("❌ [CREATE_USER] Erreur bcrypt: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur traitement mot de passe"}) + return + } + user.Password = string(hashed) + if err := database.CreateUser(&user); err != nil { log.Printf("❌ [CREATE_USER] Erreur: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Erreur création"})