Documentation
¶
Overview ¶
Package sqs is an Amazon SQS-backed babelqueue.Transport for the BabelQueue Go runtime. Producing sends the canonical envelope as the message body and projects the contract envelope fields onto native SQS MessageAttributes (bq-job = URN, bq-trace-id = trace_id, bq-message-id = meta.id, plus bq-schema-version / bq-source-lang / bq-created-at) — so a PHP/Python/... peer can route on bq-job and correlate on bq-trace-id without parsing the body. Consuming uses the visibility-timeout reservation model (ReceiveMessage → process → DeleteMessage); the authoritative attempt count is the broker's ApproximateReceiveCount, reconciled onto the envelope as attempts = count − 1.
tr, _ := sqs.New(ctx, sqs.WithRegion("eu-central-1"))
app := babelqueue.NewApp(tr, babelqueue.WithDefaultQueue("orders"))
This binding implements §3 of the BabelQueue broker-bindings contract. The envelope is unchanged (schema_version stays 1); SQS is purely additive.
It also implements the optional babelqueue.HeaderPublisher capability: out-of-band transport headers (e.g. a W3C traceparent for cross-hop span linkage, ADR-0028, or the bq-replay-bypass marker, ADR-0027) ride as String MessageAttributes beside the frozen envelope — never in it (GR-1) — and are surfaced back to the consumer on babelqueue.ReceivedMessage.Headers.
Before the attempts reconcile, a bq-schema-version message attribute that is present but not the core's supported version is version-gated (§3.7): the body is not decoded and the message is routed to a reserved unsupported-version URN no handler owns, so the App dead-letters it directly, with no retry (whatever the unknown-URN strategy, StrategyRelease included). With dead-lettering off it is not deleted: the transport's Transport.SettleNative leaves it to SQS (visibility expiry redelivers it, the queue's RedrivePolicy moves it to the native DLQ after maxReceiveCount); a poison body takes the same native settle on the first delivery. The optional OnSchemaVersionRejected hook names the rejected version.
Full spec: https://babelqueue.com
Index ¶
- Constants
- Variables
- type API
- type OnSchemaVersionRejected
- type Option
- func WithClient(client API) Option
- func WithContentDedup(enabled bool) Option
- func WithEndpoint(endpoint string) Option
- func WithFIFO(enabled bool) Option
- func WithMessageGroupID(id string) Option
- func WithOnSchemaVersionRejected(fn OnSchemaVersionRejected) Option
- func WithQueueURLPrefix(prefix string) Option
- func WithRegion(region string) Option
- func WithVisibilityTimeout(seconds int32) Option
- func WithWaitTimeSeconds(seconds int32) Option
- type Transport
- func (t *Transport) Ack(ctx context.Context, msg *babelqueue.ReceivedMessage) error
- func (t *Transport) DeadLetterQueueName(queue, suffix string) string
- func (t *Transport) Pop(ctx context.Context, queue string, timeout time.Duration) (*babelqueue.ReceivedMessage, error)
- func (t *Transport) Publish(ctx context.Context, queue, body string) error
- func (t *Transport) PublishDelayed(ctx context.Context, queue, body string, delay time.Duration) error
- func (t *Transport) PublishWithHeaders(ctx context.Context, queue, body string, headers map[string]string) error
- func (t *Transport) Release(ctx context.Context, msg *babelqueue.ReceivedMessage, delay time.Duration) error
- func (t *Transport) SettleNative(context.Context, *babelqueue.ReceivedMessage, string, string) error
- type VisibilityAPI
Constants ¶
const MaxDelaySeconds = 900
MaxDelaySeconds is the SQS ceiling for a per-message DelaySeconds (15 min, §3.4).
const MaxVisibilityTimeoutSeconds = 43200
MaxVisibilityTimeoutSeconds is SQS's ceiling for a visibility timeout (12 h).
Variables ¶
var ErrInvalidDelay = errors.New("babelqueue/sqs: delay not supported by this queue (§3.4)")
ErrInvalidDelay is returned by Transport.PublishDelayed when the delay cannot be honoured without silently dropping or truncating it: more than MaxDelaySeconds, or any positive per-message delay on a FIFO queue (SQS FIFO supports only a queue-level delay).
var ErrReleaseUnsupported = fmt.Errorf("babelqueue/sqs: release needs ChangeMessageVisibility and a receipt handle: %w", babelqueue.ErrReleaseUnsupported)
ErrReleaseUnsupported is returned by Transport.Release when the injected client does not implement VisibilityAPI, or the message has no receipt handle. It wraps babelqueue.ErrReleaseUnsupported, which is what makes the App fall back.
Functions ¶
This section is empty.
Types ¶
type API ¶
type API interface {
SendMessage(ctx context.Context, in *awssqs.SendMessageInput, optFns ...func(*awssqs.Options)) (*awssqs.SendMessageOutput, error)
ReceiveMessage(ctx context.Context, in *awssqs.ReceiveMessageInput, optFns ...func(*awssqs.Options)) (*awssqs.ReceiveMessageOutput, error)
DeleteMessage(ctx context.Context, in *awssqs.DeleteMessageInput, optFns ...func(*awssqs.Options)) (*awssqs.DeleteMessageOutput, error)
GetQueueUrl(ctx context.Context, in *awssqs.GetQueueUrlInput, optFns ...func(*awssqs.Options)) (*awssqs.GetQueueUrlOutput, error)
}
API is the subset of the AWS SQS client the transport uses. The concrete *github.com/aws/aws-sdk-go-v2/service/sqs.Client satisfies it; a fake satisfies it in tests.
type OnSchemaVersionRejected ¶ added in v1.10.0
type OnSchemaVersionRejected func(version, queue string)
OnSchemaVersionRejected is called when the version gate (§3.7) quarantines a message whose bq-schema-version attribute is present but not the core's supported version. version is the raw attribute value and queue the queue it was received from. The gate runs before the body is decoded; the App's quarantine error names the reserved route, and this hook additionally hands an operator the rejected version and queue directly (including for a body that is not valid JSON). It is a diagnostic hook: a panic in it is recovered and ignored, and it never changes how the message is delivered, acked or retried.
type Option ¶
type Option func(*Transport)
Option customizes New / NewWithClient.
func WithClient ¶
WithClient injects a preconfigured SQS client (or a fake in tests), bypassing AWS config loading.
func WithContentDedup ¶
WithContentDedup uses the queue's content-based deduplication instead of meta.id as the MessageDeduplicationId (FIFO only).
func WithEndpoint ¶
WithEndpoint overrides the SQS endpoint — point it at LocalStack/ElasticMQ for local/CI (e.g. "http://localhost:4566").
func WithFIFO ¶
WithFIFO marks the queue as FIFO (its name must end in ".fifo"). Sends then carry a MessageGroupId (see WithMessageGroupID, default the queue name) and, unless content-based dedup is enabled, a MessageDeduplicationId = meta.id.
func WithMessageGroupID ¶
WithMessageGroupID sets the FIFO ordering group (default: the queue name).
func WithOnSchemaVersionRejected ¶ added in v1.10.0
func WithOnSchemaVersionRejected(fn OnSchemaVersionRejected) Option
WithOnSchemaVersionRejected registers an optional OnSchemaVersionRejected hook (default: none).
func WithQueueURLPrefix ¶
WithQueueURLPrefix sets a base queue-URL so a queue name resolves to "<prefix>/<name>" without a GetQueueUrl call (e.g. "https://sqs.eu-central-1.amazonaws.com/123456789012"). When unset, the transport resolves names via GetQueueUrl and caches the result.
func WithRegion ¶
WithRegion sets the AWS region (otherwise resolved from the environment/config).
func WithVisibilityTimeout ¶
WithVisibilityTimeout sets the reservation window (seconds) applied on receive. Zero leaves the queue default.
func WithWaitTimeSeconds ¶
WithWaitTimeSeconds caps the ReceiveMessage long-poll wait (0–20). The runtime's per-iteration poll timeout still bounds it; this caps the upper limit.
type Transport ¶
type Transport struct {
// contains filtered or unexported fields
}
Transport implements babelqueue.Transport over Amazon SQS. It is safe for concurrent use; the queue-URL cache is guarded by a mutex.
func New ¶
New builds a transport, loading AWS configuration (the default credential provider chain) unless a client was injected with WithClient. Apply WithRegion/WithEndpoint to target a region or LocalStack/ElasticMQ.
func NewWithClient ¶
NewWithClient builds a transport over a preconfigured client (or fake). It never touches AWS config; useful for tests and dependency injection.
func (*Transport) Ack ¶
func (t *Transport) Ack(ctx context.Context, msg *babelqueue.ReceivedMessage) error
Ack deletes the reserved message (DeleteMessage on its receipt handle).
func (*Transport) DeadLetterQueueName ¶ added in v1.12.0
DeadLetterQueueName implements babelqueue.DeadLetterNamer: the BabelQueue DLQ of an SQS queue is "<queue>-dlq" by default and, for a FIFO queue, "<queue>-dlq.fifo". An explicit suffix (set with babelqueue.WithDeadLetterSuffix; "" means none) replaces "-dlq" and is placed before ".fifo" as well: an SQS FIFO queue name must end in ".fifo", so "orders.fifo" + "-x" is "orders-x.fifo", never "orders.fifo-x". An SQS queue name may hold only alphanumerics, hyphens and underscores (plus that one ".fifo" suffix), so the runtime-wide default "<queue>.dlq" cannot be created on SQS (ADR-0037 decision 7). An explicit babelqueue.WithDeadLetterQueue overrides all of it.
func (*Transport) Pop ¶
func (t *Transport) Pop(ctx context.Context, queue string, timeout time.Duration) (*babelqueue.ReceivedMessage, error)
Pop reserves the next message (long-poll up to timeout, capped at 20s and by WithWaitTimeSeconds). It reconciles attempts to max(body.attempts, ApproximateReceiveCount − 1) so a crash-redelivered message reflects its true delivery count. Returns (nil, nil) when no message arrives.
func (*Transport) Publish ¶
Publish sends body to queue with the contract MessageAttributes projection.
func (*Transport) PublishDelayed ¶ added in v1.11.0
func (t *Transport) PublishDelayed(ctx context.Context, queue, body string, delay time.Duration) error
PublishDelayed sends body with a per-message DelaySeconds (broker-bindings.md §3.4), rounding a fractional second up. A delay of zero or less behaves like Transport.Publish. A delay above MaxDelaySeconds, or a positive delay on a FIFO queue (WithFIFO), is rejected with ErrInvalidDelay and nothing is sent.
func (*Transport) PublishWithHeaders ¶ added in v1.1.0
func (t *Transport) PublishWithHeaders(ctx context.Context, queue, body string, headers map[string]string) error
PublishWithHeaders sends body together with out-of-band transport headers (babelqueue.HeaderPublisher). The headers ride as String MessageAttributes beside the frozen envelope (GR-1) — e.g. a W3C traceparent for cross-hop span linkage (ADR-0028) — merged on top of the contract bq-* attributes without clobbering them, and bounded by the 10-attribute SQS limit. A nil/empty map behaves exactly like Transport.Publish.
func (*Transport) Release ¶ added in v1.9.0
func (t *Transport) Release(ctx context.Context, msg *babelqueue.ReceivedMessage, delay time.Duration) error
Release implements babelqueue.Releaser per contract §3: the reserved message is neither deleted nor re-sent; its visibility timeout is set to delay (whole seconds, clamped to 0–43200) via ChangeMessageVisibility, so SQS redelivers the same message after the backoff (0 = redeliver now). The broker's ApproximateReceiveCount stays the authoritative attempt counter — it is reconciled onto attempts on the next Pop and surfaced as babelqueue.ReceivedMessage.DeliveryCount, which bounds retries even for a body that does not decode.
func (*Transport) SettleNative ¶ added in v1.12.0
func (t *Transport) SettleNative(context.Context, *babelqueue.ReceivedMessage, string, string) error
SettleNative implements babelqueue.NativeSettler (ADR-0037 decisions 1 and 2): a version-gated delivery or a poison body that the App may neither process nor drop, with dead-lettering off, is left to SQS itself. It deliberately does nothing: no DeleteMessage, no ChangeMessageVisibility, no re-send. The message becomes visible again when its visibility timeout lapses (the gate or the poison check rejects it again), and the queue's RedrivePolicy moves it to the native DLQ once maxReceiveCount is reached; without a RedrivePolicy it is redelivered until the retention period ends. The body and its attributes are never touched, and the App has already logged the event.
type VisibilityAPI ¶ added in v1.9.0
type VisibilityAPI interface {
ChangeMessageVisibility(ctx context.Context, in *awssqs.ChangeMessageVisibilityInput, optFns ...func(*awssqs.Options)) (*awssqs.ChangeMessageVisibilityOutput, error)
}
VisibilityAPI is the optional client capability used by Transport.Release: ChangeMessageVisibility on a receipt handle (contract §3 release/nack). The concrete *github.com/aws/aws-sdk-go-v2/service/sqs.Client satisfies it. It is kept separate from API so existing API implementations stay valid; a client without it makes Release return ErrReleaseUnsupported and the runtime falls back to re-publish + delete.