P1.1: per-queue блокировки вместо глобального лока на операции с очередью
Все операции с содержимым очереди (send/receive/delete/visibility/purge/attributes/ tags/admin/gauge/tick) переведены на per-queue RWMutex (QueueStore.GetLocked/ GetRLocked + queue.LockMu). Глобальный SyncQueues-лок остался только для map и неизменяемых полей. DLQ-переносы берут лок DLQ отдельно (порядок main→DLQ). marshalQueueMeta больше не мутирует очередь (DTO-снапшот). Устранён дедлок create_queue (setQueueAttributesV1 вызывается вне глобального лока). Добавлены конкурентные тесты; go test -race зелёный. Снимает боттлнек: синхронный Redis-I/O больше не держит глобальный лок.
This commit is contained in:
@@ -37,18 +37,25 @@ func StartGaugeUpdater(interval time.Duration, quit <-chan bool) {
|
||||
// updateGauges — пересчитывает sqs_queues_count и sqs_messages_count per tenant.
|
||||
// Формат ключа очереди: "{accessKey}:{queueName}" — берём часть до первого ":".
|
||||
func updateGauges() {
|
||||
// Собираем данные под RLock — не блокируем запись
|
||||
// Снимок указателей под коротким RLock, затем содержимое — под per-queue RLock
|
||||
models.SyncQueues.RLock()
|
||||
snapshot := make(map[string]*models.Queue, len(models.SyncQueues.Queues))
|
||||
for key, queue := range models.SyncQueues.Queues {
|
||||
snapshot[key] = queue
|
||||
}
|
||||
models.SyncQueues.RUnlock()
|
||||
|
||||
tenantQueues := make(map[string]int)
|
||||
tenantMessages := make(map[string]int)
|
||||
for key, queue := range models.SyncQueues.Queues {
|
||||
for key, queue := range snapshot {
|
||||
// Ключ формата "accessKey:queueName" — tenant определяется по accessKey
|
||||
parts := strings.SplitN(key, ":", 2)
|
||||
tenantKey := parts[0]
|
||||
tenantQueues[tenantKey]++
|
||||
queue.RLockMu()
|
||||
tenantMessages[tenantKey] += len(queue.Messages)
|
||||
queue.RUnlockMu()
|
||||
}
|
||||
models.SyncQueues.RUnlock()
|
||||
|
||||
// Сбрасываем старые значения и записываем новые
|
||||
QueuesGauge.Reset()
|
||||
|
||||
Reference in New Issue
Block a user