fix: 7 performance/correctness fixes — v0.1.20

1. Убрано логирование тела сообщения (256KB I/O на каждый send — perf+security)
2. SentTimestamp исправлен: m.SentTime вместо time.Now() (баг)
3. MD5 не пересчитывается на ReceiveMessage — используется кэш из SendMessage
4. ChangeMessageVisibility/batch теперь персистит в Redis (баг — потеря данных)
5. MessageDoesNotExist error code: QueueExists → ReceiptHandleIsInvalid (copy-paste баг)
6. copystructure убран из GetQueueAttributes — простой map lookup
7. SNS dead code удалён (SnsErrors, SnsErrorType — не используется в SQS сервисе)

Tested: quick_test 31/31 PASS, deployed v0.1.20
This commit is contained in:
Naeel
2026-04-11 20:39:08 +03:00
parent c580101f0c
commit eba01c9580
9 changed files with 61 additions and 79 deletions
+34 -35
View File
@@ -1,4 +1,4 @@
// Изменено: 2026-04-09
// Изменено: 2026-04-11 — убрана зависимость от copystructure (лишняя аллокация)
// GetQueueAttributesV1 — возвращает атрибуты очереди тенанта.
package gosqs
@@ -11,7 +11,6 @@ import (
"shared-sqs/app/interfaces"
"shared-sqs/app/models"
"shared-sqs/app/utils"
"github.com/mitchellh/copystructure"
log "github.com/sirupsen/logrus"
)
@@ -32,29 +31,29 @@ if t == nil {
return utils.CreateErrorResponseV1("InvalidClientTokenId", true)
}
requestedAttributes := func() map[string]bool {
attrs := map[string]bool{}
if len(requestBody.AttributeNames) == 0 {
return map[string]bool{"All": true}
}
for _, attr := range requestBody.AttributeNames {
if "All" == attr {
return map[string]bool{"All": true}
}
attrs[attr] = true
}
return attrs
}()
// Определяем набор запрошенных атрибутов (или All)
requestedAttributes := func() map[string]bool {
attrs := map[string]bool{}
if len(requestBody.AttributeNames) == 0 {
return map[string]bool{"All": true}
}
for _, attr := range requestBody.AttributeNames {
if "All" == attr {
return map[string]bool{"All": true}
}
attrs[attr] = true
}
return attrs
}()
dupe, _ := copystructure.Copy(models.AvailableQueueAttributes)
includedAttributes, _ := dupe.(map[string]bool)
_, ok = requestedAttributes["All"]
if !ok {
for attr := range includedAttributes {
if _, ok := requestedAttributes[attr]; !ok {
delete(includedAttributes, attr)
}
}
// Фильтруем атрибуты без deep copy — простая проверка через map lookup
_, wantAll := requestedAttributes["All"]
shouldInclude := func(attr string) bool {
if wantAll {
return true
}
_, ok := requestedAttributes[attr]
return ok
}
uriSegments := strings.Split(requestBody.QueueUrl, "/")
@@ -72,37 +71,37 @@ log.Errorf("Get Queue Attributes: %s queue does not exist for tenant %s", queueN
return utils.CreateErrorResponseV1("QueueNotFound", true)
}
if _, ok := includedAttributes["DelaySeconds"]; ok {
if shouldInclude("DelaySeconds") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "DelaySeconds", Value: strconv.Itoa(queue.DelaySeconds)})
}
if _, ok := includedAttributes["MaximumMessageSize"]; ok {
if shouldInclude("MaximumMessageSize") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "MaximumMessageSize", Value: strconv.Itoa(queue.MaximumMessageSize)})
}
if _, ok := includedAttributes["MessageRetentionPeriod"]; ok {
if shouldInclude("MessageRetentionPeriod") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "MessageRetentionPeriod", Value: strconv.Itoa(queue.MessageRetentionPeriod)})
}
if _, ok := includedAttributes["ReceiveMessageWaitTimeSeconds"]; ok {
if shouldInclude("ReceiveMessageWaitTimeSeconds") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "ReceiveMessageWaitTimeSeconds", Value: strconv.Itoa(queue.ReceiveMessageWaitTimeSeconds)})
}
if _, ok := includedAttributes["VisibilityTimeout"]; ok {
if shouldInclude("VisibilityTimeout") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "VisibilityTimeout", Value: strconv.Itoa(queue.VisibilityTimeout)})
}
if _, ok := includedAttributes["ApproximateNumberOfMessages"]; ok {
if shouldInclude("ApproximateNumberOfMessages") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessages", Value: strconv.Itoa(len(queue.Messages))})
}
if _, ok := includedAttributes["ApproximateNumberOfMessagesNotVisible"]; ok {
if shouldInclude("ApproximateNumberOfMessagesNotVisible") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "ApproximateNumberOfMessagesNotVisible", Value: strconv.Itoa(numberOfHiddenMessagesInQueue(*queue))})
}
if _, ok := includedAttributes["CreatedTimestamp"]; ok {
if shouldInclude("CreatedTimestamp") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "CreatedTimestamp", Value: "0000000000"})
}
if _, ok := includedAttributes["LastModifiedTimestamp"]; ok {
if shouldInclude("LastModifiedTimestamp") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "LastModifiedTimestamp", Value: "0000000000"})
}
if _, ok := includedAttributes["QueueArn"]; ok {
if shouldInclude("QueueArn") {
queueAttributes = append(queueAttributes, models.Attribute{Name: "QueueArn", Value: queue.Arn})
}
if _, ok := includedAttributes["RedrivePolicy"]; ok && queue.DeadLetterQueue != nil {
if shouldInclude("RedrivePolicy") && queue.DeadLetterQueue != nil {
queueAttributes = append(queueAttributes, models.Attribute{
Name: "RedrivePolicy",
Value: fmt.Sprintf(`{"maxReceiveCount":"%d", "deadLetterTargetArn":"%s"}`, queue.MaxReceiveCount, queue.DeadLetterQueue.Arn),