gobridge

Scenario 2: SQS-to-SQS Queue Bridge

A stateless transport bridge – routes messages between two AWS SQS queues without sessions.

Use Case

You have an ingestion queue receiving events from upstream producers and need to route those messages to a processing queue consumed by a downstream microservice. Both queues are standard SQS queues in the same AWS region.

Architecture

flowchart LR
    Q1["SQS Queue\ningestion-events"]
    Q2["SQS Queue\nprocessing-events"]

    Q1 -->|ReceiveMessage\nlong-poll| R[Receiver\nsqs-in]
    R --> Route[Route\nforward]
    Route --> S[Sender\nsqs-out]
    S -->|SendMessageBatch| Q2

    style Route fill:#f96,stroke:#333

Configuration

bridge:
  id: sqs-forwarder

receivers:
  - id: sqs-in
    transport: sqs
    options:
      queue_url: https://sqs.us-west-1.amazonaws.com/123456789/ingestion-events
      region: us-west-1
      max_messages: 10
      wait_time_seconds: 20
      visibility_timeout: 60
      auto_extend: true

senders:
  - id: sqs-out
    transport: sqs
    options:
      queue_url: https://sqs.us-west-1.amazonaws.com/123456789/processing-events
      region: us-west-1
      batch_size: 10

bindings:
  - id: to-processing
    sender_id: sqs-out
    address: processing-events

stores:
  # The default policy dead-letters permanent failures and expired messages;
  # a route that says so needs a store to write them to.
  dlq:
    type: sqlite
    options:
      path: /var/lib/gobridge/dlq.db

routes:
  - id: forward
    receiver_id: sqs-in
    delivery_mode: direct_hold
    dispatch_mode: single
    bindings: [to-processing]

Config Walkthrough

No Sessions

SQS is a stateless transport. Unlike MQTT, there’s no persistent connection to manage. Each receive and send operation is an independent HTTP API call. This means:

receivers

senders

Note on the SQS binding address. An SQS sender is pinned to one queue via its queue_url or queue_name. The binding address may be the bare queue name (as here, processing-events) or the full queue URL – either form is matched to that bound queue. It names the sender’s queue rather than routing per message.

SQS Polling Lifecycle

sequenceDiagram
    participant Bridge as GoBridge Receiver
    participant SQS as SQS Queue

    loop Every poll cycle
        Bridge->>SQS: ReceiveMessage(max=10, wait=20s)
        SQS-->>Bridge: 0-10 messages

        alt Messages received
            Bridge->>Bridge: Process via route
            Bridge->>SQS: DeleteMessage (ACK)
        end

        opt auto_extend at one-third of visibility
            Bridge->>SQS: ChangeMessageVisibility
        end
    end

Go Bootstrap

reg := ports.NewRegistry()
_ = sqs.Register(reg) // register the linked adapter's config decoder

cfg, _ := cfgparser.ParseFile("bridge.yaml", cfgparser.FormatAuto, reg)

rt, _ := bridge.NewBuilder(cfg, bridge.WithLogger(logger)).
    RegisterTransportFactory("sqs", sqs.NewFactory(logger)).
    Build(ctx)

rt.Start(ctx)

Variations

Using Queue Names (Auto-Resolve)

If you prefer logical names over URLs, the SQS adapter resolves them at startup:

receivers:
  - id: sqs-in
    transport: sqs
    options:
      queue_name: ingestion-events
      region: us-west-1

Custom Endpoint (LocalStack)

For local development with LocalStack:

receivers:
  - id: sqs-in
    transport: sqs
    options:
      queue_url: http://localhost:4566/000000000000/ingestion-events
      endpoint: http://localhost:4566
      region: us-west-1

FIFO Queues

For ordered, exactly-once processing:

senders:
  - id: sqs-out
    transport: sqs
    options:
      queue_url: https://sqs.us-west-1.amazonaws.com/123456789/events.fifo
      fifo: true
      message_group_id: default-group
      batch_size: 10

The message_group_id determines ordering scope. Messages in the same group are delivered in order. Use fifo: true to enable FIFO semantics even when the group ID comes from envelope headers.

SNS Unwrapping

When SQS receives messages via an SNS subscription, they arrive wrapped in an SNS envelope. Enable unwrapping to extract the original message:

receivers:
  - id: sqs-in
    transport: sqs
    options:
      queue_url: https://sqs.us-west-1.amazonaws.com/123456789/events
      sns_unwrap: true

AWS Profile Selection

Use a specific AWS shared-config profile:

receivers:
  - id: sqs-in
    transport: sqs
    options:
      queue_name: ingestion-events
      region: us-west-1
      profile: production