Files
SQS-service/app/gosqs/memory_guard.go
T
Repinoid 521e3d85d0 fix(concurrency,durability): address Opus review critical findings
- create_queue: SaveQueue under per-queue lock, not global SyncQueues.Lock
  (fixes fatal concurrent map iteration/write on idempotent CreateQueue of existing FIFO queue)
- delete_message_batch: reject empty ReceiptHandle (JSON protocol bypass deleted all unreceived msgs)
- send_message/send_message_batch: register dedupId only after successful persist
  (retry with same dedupId no longer returns 200 without persisting)
- memory_guard: global HeapAlloc guard (SHARED_SQS_MAX_HEAP_MB, 0=off) in send paths
2026-10-10 17:07:52 +03:00

38 lines
1.5 KiB
Go

// app/gosqs/memory_guard.go
// Глобальный предохранитель памяти процесса (защита от OOM одним тенантом).
//
// Лимиты по числу сообщений (MaxMessagesForQueue) не ограничивают СУММАРНЫЙ
// объём: 120k × 256 КБ ≈ 30 ГБ на одну очередь. Этот предохранитель отказывает
// в SendMessage/SendMessageBatch по HeapAlloc выше порога — единственная защита
// процесса от суммы всех тенантов.
//
// Задаётся env `SHARED_SQS_MAX_HEAP_MB` (0 = выключен). По умолчанию выключен:
// конкретное число зависит от RAM ВМ и целевого числа тенантов (решение владельца).
// Рекомендация на старт: ~70% от RAM ВМ, напр. 1024 для 1.5 ГБ ВМ.
package gosqs
import (
"os"
"runtime"
"strconv"
)
// maxHeapBytes — порог HeapAlloc в байтах; 0 = предохранитель выключен.
var maxHeapBytes = func() int64 {
mb, err := strconv.ParseInt(os.Getenv("SHARED_SQS_MAX_HEAP_MB"), 10, 64)
if err != nil || mb <= 0 {
return 0
}
return mb * 1024 * 1024
}()
// heapOverLimit — true, если текущий HeapAlloc превышает порог.
func heapOverLimit() bool {
if maxHeapBytes <= 0 {
return false
}
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
return int64(ms.HeapAlloc) > maxHeapBytes
}