Phase 1 (Critical): - #1 JWT auth (done in v0.1.16) - #2 Batch message size validation in send_message_batch.go - #10 RLock in GetQueueUrlV1 (data race fix) Phase 2 (AWS-compatible limits): - #3 QueueName validation: max 80 chars, [a-zA-Z0-9_-](.fifo)? - #4 WaitTimeSeconds clamped to 0-20 - #5 ReceiveMessageWaitTimeSeconds clamped to 0-20 - #6 DelaySeconds clamped to 0-900 - #7 VisibilityTimeout clamped to 0-43200 - #8 MaxNumberOfMessages clamped to 1-10 - #9 Message attributes limited to 10 per message - #15 BatchEntryId length validated (max 80) - #16 DeduplicationID length validated (max 128) - #17 GroupID length validated (max 128) Phase 3 (Per-tenant resource limits): - #11 Max messages per queue (120K standard, 20K FIFO) - #12 Global tenant limit (1000) - #3.5 HTTP request body size limit (1MB via MaxBytesReader) Phase 4 (Stability): - #14 Duplicates map cleanup (already in PeriodicTasks) - #13 FIFO group lock timeout (already in visibility timeout reset) - #18 Redis size guard: skip save if >50MB Skipped (Low, no real risk): - #19 {account} URL param (informational only, not used for access) - #20 ReceiptHandle format (self-validating UUID#UUID) New file: app/gosqs/validation.go — centralized AWS SQS limits and validators
122 lines
3.9 KiB
Go
122 lines
3.9 KiB
Go
// app/gosqs/validation.go
|
|
// AWS SQS-совместимые валидации параметров.
|
|
// Все лимиты берутся из спецификации AWS SQS — не придумываем свои.
|
|
// Created: 2026-04-10
|
|
package gosqs
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
)
|
|
|
|
// ── AWS SQS лимиты ────────────────────────────────────────────────────────────
|
|
const (
|
|
// Очередь
|
|
MaxQueueNameLength = 80
|
|
MaxMessageSizeDefault = 262144 // 256 KB
|
|
MaxMessageSizeLimit = 262144
|
|
MinMessageSizeLimit = 1024 // 1 KB
|
|
|
|
// Атрибуты очереди
|
|
MaxDelaySeconds = 900 // 15 min
|
|
MaxVisibilityTimeout = 43200 // 12 hours
|
|
MaxReceiveMessageWaitTimeSeconds = 20 // long polling cap
|
|
MinMessageRetentionPeriod = 60 // 1 min
|
|
MaxMessageRetentionPeriod = 1209600 // 14 days
|
|
|
|
// Receive
|
|
MaxNumberOfMessagesLimit = 10
|
|
MinNumberOfMessagesLimit = 1
|
|
|
|
// Message attributes
|
|
MaxMessageAttributes = 10
|
|
MaxMessageAttributeSize = 262144 // 256 KB суммарно (тело + атрибуты)
|
|
|
|
// Deduplication / GroupID
|
|
MaxDeduplicationIDLength = 128
|
|
MaxGroupIDLength = 128
|
|
|
|
// Batch
|
|
MaxBatchEntryIDLength = 80
|
|
|
|
// Per-queue message limit (AWS = 120,000 для standard, 20,000 для FIFO)
|
|
MaxMessagesPerQueue = 120000
|
|
MaxMessagesPerFIFOQueue = 20000
|
|
|
|
// Per-request body size limit
|
|
MaxRequestBodySize = 1 * 1024 * 1024 // 1 MB
|
|
|
|
// Global tenant limit
|
|
MaxTenantsDefault = 1000
|
|
)
|
|
|
|
// queueNameRegex — допустимые символы для имени очереди (AWS SQS)
|
|
var queueNameRegex = regexp.MustCompile(`^[a-zA-Z0-9_-]+(\.fifo)?$`)
|
|
|
|
// ValidateQueueName — проверяет имя очереди по AWS правилам:
|
|
// макс 80 символов, только [a-zA-Z0-9_-], опционально суффикс .fifo
|
|
func ValidateQueueName(name string) error {
|
|
if name == "" {
|
|
return fmt.Errorf("QueueName is required")
|
|
}
|
|
if len(name) > MaxQueueNameLength {
|
|
return fmt.Errorf("QueueName exceeds %d characters", MaxQueueNameLength)
|
|
}
|
|
if !queueNameRegex.MatchString(name) {
|
|
return fmt.Errorf("QueueName contains invalid characters")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ClampInt — ограничивает значение в диапазоне [min, max].
|
|
// Если val < min — возвращает min, если > max — возвращает max.
|
|
func ClampInt(val, min, max int) int {
|
|
if val < min {
|
|
return min
|
|
}
|
|
if val > max {
|
|
return max
|
|
}
|
|
return val
|
|
}
|
|
|
|
// ValidateDeduplicationID — проверяет длину deduplication ID (макс 128 chars по AWS)
|
|
func ValidateDeduplicationID(id string) error {
|
|
if len(id) > MaxDeduplicationIDLength {
|
|
return fmt.Errorf("MessageDeduplicationId exceeds %d characters", MaxDeduplicationIDLength)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateGroupID — проверяет длину group ID (макс 128 chars по AWS)
|
|
func ValidateGroupID(id string) error {
|
|
if len(id) > MaxGroupIDLength {
|
|
return fmt.Errorf("MessageGroupId exceeds %d characters", MaxGroupIDLength)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateBatchEntryID — проверяет длину batch entry ID (макс 80 chars)
|
|
func ValidateBatchEntryID(id string) error {
|
|
if len(id) > MaxBatchEntryIDLength {
|
|
return fmt.Errorf("BatchEntryId exceeds %d characters", MaxBatchEntryIDLength)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ValidateMessageAttributes — проверяет количество атрибутов (макс 10 по AWS)
|
|
func ValidateMessageAttributes(attrs map[string]interface{}) error {
|
|
if len(attrs) > MaxMessageAttributes {
|
|
return fmt.Errorf("message attributes exceed limit of %d", MaxMessageAttributes)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MaxMessagesForQueue — возвращает лимит сообщений для очереди (FIFO или standard)
|
|
func MaxMessagesForQueue(isFIFO bool) int {
|
|
if isFIFO {
|
|
return MaxMessagesPerFIFOQueue
|
|
}
|
|
return MaxMessagesPerQueue
|
|
}
|