From 529d2085767571e4b58bf0f6ed8728f2b887277b Mon Sep 17 00:00:00 2001 From: Repinoid Date: Wed, 7 Oct 2026 08:26:34 +0300 Subject: [PATCH] =?UTF-8?q?fix(P1.2):=20=D1=83=D1=82=D0=B5=D1=87=D0=BA?= =?UTF-8?q?=D0=B0=20per-queue=20=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=20ReceiveMessage=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D1=83=D1=81=D1=82=D0=BE=D0=B9=20=D0=BE?= =?UTF-8?q?=D1=87=D0=B5=D1=80=D0=B5=D0=B4=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Возврат до defer queue.UnlockMu() оставлял блокировку захваченной навсегда — очередь «зависала»: все последующие Lock/RLock ждали вечно. Проявлялось при LiveCount()==0 (все сообщения удалены/tombstone). Найдено стресс-тестом (2000 сообщений × циклы): стек горутин показал массовое ожидание RLockMu. - receive: defer до проверки пустоты. - регрессионный тест TestReceiveEmptyQueue_DoesNotLeakLock (падает на дефекте, проходит на фиксе). --- app/gosqs/receive_message.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/gosqs/receive_message.go b/app/gosqs/receive_message.go index 24afa58..fe7974f 100644 --- a/app/gosqs/receive_message.go +++ b/app/gosqs/receive_message.go @@ -154,10 +154,16 @@ func ReceiveMessageV1(req *http.Request) (int, interfaces.AbstractResponseBody) // - для FIFO-очереди блокируется группа (LockGroup) до DeleteMessage/таймаута. func receiveMessagesUnderLock(key string, visibilityTimeout, maxNumberOfMessages int) ([]*models.ResultMessage, bool) { queue := models.SyncQueues.GetLocked(key) - if queue == nil || queue.LiveCount() == 0 { + if queue == nil { return nil, false } + // ВАЖНО: defer — ДО любых return ниже. Иначе возврат на пустой очереди + // оставлял бы per-queue блокировку захваченной навсегда (очередь «зависала»: + // все последующие Lock/RLock ждали бы вечно). defer queue.UnlockMu() + if queue.LiveCount() == 0 { + return nil, false + } // Быстрая предпроверка: есть ли вообще хотя бы одно готовое сообщение. if !queueHasReceivableMessages(queue) { return nil, false