diff --git a/app/gosqs/queue_attributes.go b/app/gosqs/queue_attributes.go index 341db23..149ed82 100644 --- a/app/gosqs/queue_attributes.go +++ b/app/gosqs/queue_attributes.go @@ -84,6 +84,21 @@ func setQueueAttributesV1(q *models.Queue, attr models.QueueAttributes, provided log.Error("Invalid RedrivePolicy Attribute") return fmt.Errorf("InvalidAttributeValue") } + // Запрет self-DLQ (q → q) и циклов (A → B → A): при переносе в DLQ + // переносящий код берёт DeadLetterQueue.LockMu() под уже взятым q.mu — + // self/цикл даёт немедленный self-deadlock (или AB/BA-deadlock). + if deadLetterQueue == q { + log.Error("Invalid RedrivePolicy Attribute: self DLQ") + return fmt.Errorf("InvalidAttributeValue") + } + // Обход цепочки DLQ для детекта циклов. Лимит 100 — защита от уже + // существующего в данных цикла (если бы он там был). + for cur, steps := deadLetterQueue, 0; cur != nil && steps < 100; cur, steps = cur.DeadLetterQueue, steps+1 { + if cur == q { + log.Error("Invalid RedrivePolicy Attribute: cyclic DLQ") + return fmt.Errorf("InvalidAttributeValue") + } + } q.DeadLetterQueue = deadLetterQueue q.MaxReceiveCount = attr.RedrivePolicy.MaxReceiveCount.Int() }