sqs

sqs covers the AWS SQS send, receive, decode and acknowledge workflow, validating FIFO constraints before any AWS configuration is loaded.

Part of nurago, a collection of independent Go packages for backend services.

import "github.com/tecnickcom/nurago/pkg/sqs"

Send, receive, decode and delete against an SQS queue, on aws-sdk-go-v2.

c, err := sqs.New(ctx, queueURL, "")

err = c.SendData(ctx, payload)
msg, err := c.Receive(ctx)
err = c.Delete(ctx, msg.ReceiptHandle)

FIFO constraints are checked at construction

New takes a queue URL and a message-group ID, and validates the combination before any AWS configuration is loaded:

  • The queue URL must be a valid absolute URL.
  • A FIFO queue, whose URL ends in .fifo, requires a message-group ID.
  • A standard queue requires the group ID to be empty; a non-empty value is rejected with ErrUnexpectedMessageGroupID.

Validating first means a misconfiguration fails immediately with a specific error, rather than surfacing later as an AWS API rejection whose message does not name the actual problem.

The group ID requirement is the one that catches people. FIFO ordering is guaranteed within a message group, not across the queue, so the group ID is what determines the ordering domain. Omitting it is not a detail SQS will fill in.

Deduplication on FIFO queues

Send and SendData do not set a MessageDeduplicationId.

That means a FIFO queue must have ContentBasedDeduplication enabled, or SQS rejects the message. If it is not enabled, or if two logically distinct messages can have identical content, use SendWithDeduplicationID or SendDataWithDeduplicationID and supply one.

The distinction matters more than it looks. Content-based deduplication hashes the body, so two genuinely separate events with the same payload, such as two identical “retry this job” messages five minutes apart, are silently collapsed into one inside the deduplication window. A per-message ID from stringkey or random avoids that.

Region comes from the queue URL

The AWS region is derived from the queue URL when not set explicitly, and an explicit region through WithAWSOptions still wins.

An SQS queue URL contains its region, so requiring it separately creates a configuration that can contradict itself. Deriving it removes the case where a queue URL is moved to a new region and a signing mismatch appears instead of a clear error.

Long polling is on by default

WithWaitTimeSeconds defaults to 20 seconds, which is long polling rather than short polling.

Short polling returns immediately, often empty, so a receive loop becomes a busy loop of billable API calls that also sometimes misses messages present on other servers. Long polling waits for a message to arrive, which cuts both the API call count and the delivery latency. Twenty seconds is the SQS maximum, and the right default.

WithVisibilityTimeout sets how long a received message is hidden from other consumers. It must exceed your processing time, or the message becomes visible again while you are still working on it and a second consumer picks it up.

Delete is the acknowledgement

SQS has no acknowledgement primitive. A message stays on the queue until it is deleted, and reappears after the visibility timeout if it is not.

So Delete is the commit, and its placement decides the delivery semantics. Delete after processing succeeds for at-least-once, which is the usual choice and requires idempotent handlers. Delete on receipt for at-most-once, which loses messages on a crash.

Dependencies

Reaches github.com/aws/aws-sdk-go-v2/service/sqs, plus awsopt.