diff --git a/internal/service/consumer/consumer.go b/internal/service/consumer/consumer.go index 0c3c5a8..de8f0f2 100644 --- a/internal/service/consumer/consumer.go +++ b/internal/service/consumer/consumer.go @@ -155,9 +155,32 @@ func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, store * log.Error("consumer: flush failed — сообщения НЕ удалены, вернутся после visibility timeout", "err", err) continue } - for _, p := range pending { - if err := deleteMessage(ctx, sqsClient, queueURL, p.handle, log); err != nil { - log.Error("consumer: DeleteMessage failed", "err", err, "message_id", p.id) + // DeleteMessageBatch: до 10 записей за вызов (было по одному DeleteMessage + // на сообщение — лишние round-trip, ревью 2026-10-10). + for i := 0; i < len(pending); i += 10 { + end := i + 10 + if end > len(pending) { + end = len(pending) + } + chunk := pending[i:end] + entries := make([]sqstypes.DeleteMessageBatchRequestEntry, 0, len(chunk)) + for j := range chunk { + entries = append(entries, sqstypes.DeleteMessageBatchRequestEntry{ + Id: aws.String(strconv.Itoa(j)), + ReceiptHandle: aws.String(chunk[j].handle), + }) + } + out, err := sqsClient.DeleteMessageBatch(ctx, &sqs.DeleteMessageBatchInput{ + QueueUrl: aws.String(queueURL), + Entries: entries, + }) + if err != nil { + log.Error("consumer: DeleteMessageBatch failed", "err", err, "count", len(chunk)) + continue + } + for _, f := range out.Failed { + log.Error("consumer: DeleteMessageBatch entry failed", + "id", aws.ToString(f.Id), "code", aws.ToString(f.Code), "msg", aws.ToString(f.Message)) } } } @@ -166,15 +189,6 @@ func Run(ctx context.Context, cfg *config.Config, sqsClient *sqs.Client, store * return nil } -// deleteMessage удаляет обработанное сообщение из очереди. -func deleteMessage(ctx context.Context, client *sqs.Client, queueURL string, receiptHandle string, log *slog.Logger) error { - _, err := client.DeleteMessage(ctx, &sqs.DeleteMessageInput{ - QueueUrl: aws.String(queueURL), - ReceiptHandle: aws.String(receiptHandle), - }) - return err -} - // sendToDLQ — кладёт битое неразборчивое сообщение в DLQ для диагностики. func sendToDLQ(ctx context.Context, client *sqs.Client, dlqURL, body string, log *slog.Logger) error { _, err := client.SendMessage(ctx, &sqs.SendMessageInput{