fix: DLQ-релинк после загрузки из Redis + безопасная эвикция retention + ParseForm

1. DLQ больше не сериализуется вложенным объектом (была detached-копия после
   загрузки + неограниченная рекурсия при цикле): в метаданных хранится только
   имя (dead_letter_queue_name), после LoadAllQueues указатель релинкуется на
   объект из map. Закрывает потерянные переносы в DLQ и чужой мьютекс.
2. Retention-эвикция: компакция НА МЕСТЕ (чтение value в i, запись в n<=i)
   вместо kept := Messages[:0] — устранён алиасинг на переиспользуемом срезе.
3. countBatchEntries: явный req.ParseForm() — корректный msg_count для батчей.
Тесты: +DLQ-перенос, +эвикция с сохранением порядка; go test -race зелёный.
This commit is contained in:
Repinoid
2026-10-07 07:18:31 +03:00
parent d53aadecfa
commit 31840b9756
4 changed files with 40 additions and 9 deletions
+7 -4
View File
@@ -79,9 +79,11 @@ func processQueueTick(key string, queue *models.Queue) {
if queue.MessageRetentionPeriod > 0 {
cutoff := time.Now().Add(-time.Duration(queue.MessageRetentionPeriod) * time.Second)
expired := make([]string, 0) // uuid просроченных сообщений для удаления из Redis
kept := queue.Messages[:0]
// Компакция НА МЕСТЕ: читаем значение в i, пишем в n (n <= i) — без
// алиасинга на переиспользуемом срезе и без лишней аллокации.
n := 0
for i := range queue.Messages {
msg := &queue.Messages[i]
msg := queue.Messages[i]
if msg.SentTime.Before(cutoff) {
expired = append(expired, msg.Uuid)
if msg.GroupID != "" {
@@ -89,10 +91,11 @@ func processQueueTick(key string, queue *models.Queue) {
}
continue
}
kept = append(kept, *msg)
queue.Messages[n] = msg
n++
}
if len(expired) > 0 {
queue.Messages = kept
queue.Messages = queue.Messages[:n]
log.Infof("Queue [%s]: evicted %d messages by MessageRetentionPeriod", queue.Name, len(expired))
// Удаляем просроченные из Redis, чтобы не воскресли после рестарта.
persistence.DeleteMessagesPersist(key, expired)