v0.1.35: устранены гонки map (ChangeVisibility/DeleteBatch) и nil-deref под Lock + OverLimit

This commit is contained in:
“Naeel”
2026-08-14 18:48:35 +04:00
parent 9cde807dda
commit c4da02c814
8 changed files with 74 additions and 44 deletions
+17 -11
View File
@@ -47,19 +47,26 @@ func ChangeMessageVisibilityV1(req *http.Request) (int, interfaces.AbstractRespo
return utils.CreateErrorResponseV1("InvalidParameterValue", true)
}
if _, ok := models.SyncQueues.Queues[key]; !ok {
// ВСЯ работа с очередью — под одним Lock.
// Раньше проверка существования шла БЕЗ блокировки (чтение map) —
// concurrent map read and map write при параллельном DeleteQueue
// (fatal error, под падал под нагрузкой).
// defer Unlock: при любой панике в секции мьютекс не останется захваченным.
models.SyncQueues.Lock()
defer models.SyncQueues.Unlock()
queue, exists := models.SyncQueues.Queues[key]
if !exists {
return utils.CreateErrorResponseV1("QueueNotFound", true)
}
models.SyncQueues.Lock()
messageFound := false
var changedMsgUuid string
var msgRemoved bool
for i := 0; i < len(models.SyncQueues.Queues[key].Messages); i++ {
queue := models.SyncQueues.Queues[key]
for i := 0; i < len(queue.Messages); i++ {
msgs := queue.Messages
if msgs[i].ReceiptHandle == receiptHandle {
timeout := models.SyncQueues.Queues[key].VisibilityTimeout
timeout := queue.VisibilityTimeout
if visibilityTimeout == 0 {
msgs[i].ReceiptTime = time.Now().UTC()
msgs[i].ReceiptHandle = ""
@@ -83,23 +90,22 @@ func ChangeMessageVisibilityV1(req *http.Request) (int, interfaces.AbstractRespo
break
}
}
// Персистим изменения в Redis под Lock
// Персистим изменения в Redis под Lock (сетевые записи асинхронны).
if messageFound {
if msgRemoved {
// Сообщение удалено (перемещено в DLQ) — удаляем из Redis
persistence.DeleteMessagePersist(key, changedMsgUuid)
} else {
// Сообщение обновлено — перезаписываем в Redis
for i := range models.SyncQueues.Queues[key].Messages {
if models.SyncQueues.Queues[key].Messages[i].Uuid == changedMsgUuid {
persistence.SaveMessage(key, &models.SyncQueues.Queues[key].Messages[i])
for i := range queue.Messages {
if queue.Messages[i].Uuid == changedMsgUuid {
persistence.SaveMessage(key, &queue.Messages[i])
break
}
}
}
persistence.SaveQueue(key, models.SyncQueues.Queues[key])
persistence.SaveQueue(key, queue)
}
models.SyncQueues.Unlock()
if !messageFound {
return utils.CreateErrorResponseV1("MessageNotInFlight", true)
}