package gosqs import ( "net/http" "strings" "time" "shared-sqs/app/interfaces" "shared-sqs/app/models" "shared-sqs/app/persistence" "shared-sqs/app/utils" log "github.com/sirupsen/logrus" ) // PurgeQueueV1 — очищает ВСЕ сообщения очереди тенанта. // // Логическая схема: // 1. Разбор тела запроса → PurgeQueueRequest. // 2. Тенант из контекста (SigV4 → AccessKey). // 3. Имя очереди из QueueUrl (последний сегмент). // 4. Под Lock: // - проверка существования очереди → QueueNotFound; // - защита от повторного purge (фикс): повторный вызов в течение 60 секунд // → PurgeQueueInProgress (требование AWS). Раньше purge можно было // вызывать без ограничений; // - очистка in-memory сообщений и dedup-записей; // - фиксация LastPurgeTime; // - асинхронная очистка Redis (DEL хэша сообщений) + SaveQueue. // 5. Ответ: пустой PurgeQueueResponse. func PurgeQueueV1(req *http.Request) (int, interfaces.AbstractResponseBody) { requestBody := models.NewPurgeQueueRequest() ok := utils.REQUEST_TRANSFORMER(requestBody, req, false) if !ok { log.Error("Invalid Request - PurgeQueueV1") return utils.CreateErrorResponseV1("InvalidParameterValue", true) } t := getTenantFromContext(req) if t == nil { return utils.CreateErrorResponseV1("InvalidClientTokenId", true) } uriSegments := strings.Split(requestBody.QueueUrl, "/") queueName := uriSegments[len(uriSegments)-1] key := tenantQueueKey(t.AccessKey, queueName) models.SyncQueues.Lock() defer models.SyncQueues.Unlock() if _, ok := models.SyncQueues.Queues[key]; !ok { log.Errorf("Purge Queue: %s, queue does not exist for tenant %s", queueName, t.ID) return utils.CreateErrorResponseV1("QueueNotFound", true) } // AWS: PurgeQueue допускается не чаще одного раза в 60 секунд на очередь. // Нулевой LastPurgeTime (purge ещё не выполнялся) → запрет не срабатывает. if time.Since(models.SyncQueues.Queues[key].LastPurgeTime) < 60*time.Second { log.Warnf("Purge Queue: %s rejected — purge in progress (last: %s)", queueName, models.SyncQueues.Queues[key].LastPurgeTime.Format(time.RFC3339)) return utils.CreateErrorResponseV1("PurgeQueueInProgress", true) } log.Infof("Purging Queue: %s (tenant: %s)", queueName, t.ID) models.SyncQueues.Queues[key].Messages = nil models.SyncQueues.Queues[key].Duplicates = make(map[string]time.Time) // Фиксируем время purge — защита от повторного вызова в течение 60 секунд. models.SyncQueues.Queues[key].LastPurgeTime = time.Now() // Удаляем все сообщения из Redis одной командой DEL persistence.PurgeMessagesPersist(key) // Сохраняем пустые метаданные очереди persistence.SaveQueue(key, models.SyncQueues.Queues[key]) respStruct := models.PurgeQueueResponse{ Xmlns: models.BaseXmlns, Metadata: models.BaseResponseMetadata, } return http.StatusOK, respStruct }