Skip to main content

Overview

The MessagingFactory creates event-driven AWS resources: SQS queues, SNS topics, and EventBridge event buses. These resources decouple application components for asynchronous communication.

Basic Usage

import { App, MessagingFactory } from "@fjall/components-infrastructure";

const app = App.getApp("myapp");

const queue = app.addMessaging(
  MessagingFactory.build("TaskQueue", {
    type: "queue",
  }),
);

Messaging Types

SQS Queue (Standard)

Standard queues for high-throughput messaging:
const queue = app.addMessaging(
  MessagingFactory.build("WorkerQueue", {
    type: "queue",
    queueType: "standard",
    visibilityTimeout: 30,
    messageRetentionPeriod: 1209600, // 14 days
  }),
);
Features:
  • Nearly unlimited throughput
  • At-least-once delivery
  • Best-effort ordering
  • Perfect for background job processing

SQS Queue (FIFO)

FIFO queues for ordered, exactly-once processing:
const queue = app.addMessaging(
  MessagingFactory.build("OrderQueue", {
    type: "queue",
    queueType: "fifo",
    contentBasedDeduplication: true,
  }),
);
Features:
  • Exactly-once processing
  • First-in-first-out ordering
  • Message deduplication
  • Perfect for ordered workflows

Dead Letter Queue

Capture failed messages for analysis:
const mainQueue = app.addMessaging(
  MessagingFactory.build("ProcessingQueue", {
    type: "queue",
    deadLetterQueue: {
      enabled: true,
      maxReceiveCount: 3, // Move to DLQ after 3 failures
    },
  }),
);

SNS Topic

Publish-subscribe messaging for fan-out patterns:
const topic = app.addMessaging(
  MessagingFactory.build("Notifications", {
    type: "topic",
  }),
);
Features:
  • Fan-out to multiple subscribers
  • Push-based delivery
  • Multiple subscriber types (SQS, Lambda, HTTP, email)
  • Message filtering

EventBridge Event Bus

Custom event bus for event-driven architectures:
const eventBus = app.addMessaging(
  MessagingFactory.build("AppEvents", {
    type: "eventBus",
  }),
);
Features:
  • Schema registry support
  • Event archiving
  • Cross-account event delivery
  • Rule-based routing

Configuration Parameters

Queue Parameters

ParameterTypeDescriptionDefault
type"queue"Resource typeRequired
queueType"standard" | "fifo"Queue type"standard"
visibilityTimeoutnumberSeconds message is hidden after receive30
messageRetentionPeriodnumberSeconds to retain messages345600 (4 days)
maxMessageSizenumberMaximum message size in bytes262144 (256 KB)
receiveMessageWaitTimenumberLong polling wait time0
deadLetterQueueobjectDead letter queue configuration-
contentBasedDeduplicationbooleanEnable content-based dedup (FIFO only)false
deliveryDelaynumberDelay in seconds before messages become visible0
encryption"SSE_KMS" | "SSE_SQS" | "NONE"Encryption type"SSE_SQS"
kmsKeyArnstringKMS key ARN for encryption (if KMS encryption)-
removalPolicy"DESTROY" | "RETAIN"What happens on stack delete"RETAIN"

Topic Parameters

ParameterTypeDescriptionDefault
type"topic"Resource typeRequired
displayNamestringDisplay name for SMS-
fifobooleanEnable FIFO topicfalse
contentBasedDeduplicationbooleanEnable dedup (FIFO only)false
topicNamestringCustom topic nameAuto-generated
removalPolicy"DESTROY" | "RETAIN"What happens on stack delete"RETAIN"

Event Bus Parameters

ParameterTypeDescriptionDefault
type"eventBus"Resource typeRequired
eventBusNamestringCustom event bus nameAuto-generated
removalPolicy"DESTROY" | "RETAIN"What happens on stack delete"RETAIN"

Common Patterns

Background Job Processing

// Job queue
const jobQueue = app.addMessaging(
  MessagingFactory.build("JobQueue", {
    type: "queue",
    visibilityTimeout: 300, // 5 min for long jobs
  }),
);

// Worker Lambda
const worker = app.addCompute(
  ComputeFactory.build("Worker", {
    type: "lambda",
    deployment: "code",
    handler: "worker.handler",
    timeout: 300,
    connections: [jobQueue],
  }),
);

Event Fan-Out

Route matching events to multiple targets with an EventBridge event bus. Call subscribe(id, { pattern, target }) on the bus, passing a queue, Lambda, or ECS service as the target. Each subscription creates an EventBridge rule scoped to the bus.
// Central event bus
const orderBus = app.addMessaging(
  MessagingFactory.build("OrderEvents", {
    type: "eventBus",
  }),
);

// Subscriber queues
const inventoryQueue = app.addMessaging(
  MessagingFactory.build("InventoryQueue", { type: "queue" }),
);

const notificationQueue = app.addMessaging(
  MessagingFactory.build("NotificationQueue", { type: "queue" }),
);

// Subscribe each queue to the bus with an event pattern
orderBus.subscribe("InventorySub", {
  pattern: { source: ["app.orders"], detailType: ["OrderPlaced"] },
  target: inventoryQueue,
});

orderBus.subscribe("NotificationSub", {
  pattern: { source: ["app.orders"], detailType: ["OrderPlaced"] },
  target: notificationQueue,
});
SNS topics support fan-out through publish/subscribe, but Fjall does not yet expose a wrapper subscription method on MessagingFactory topics. Use an EventBridge event bus for declarative fan-out, or attach SNS subscriptions directly to the underlying CDK construct via topic.getTopic().

ISR Revalidation Queue (OpenNext)

const revalidationQueue = app.addMessaging(
  MessagingFactory.build("RevalidationQueue", {
    type: "queue",
    queueType: "fifo",
    contentBasedDeduplication: true,
    visibilityTimeout: 30,
  }),
);

Connecting to Compute

Lambda with SQS Trigger

const queue = app.addMessaging(
  MessagingFactory.build("TaskQueue", { type: "queue" }),
);

const processor = app.addCompute(
  ComputeFactory.build("Processor", {
    type: "lambda",
    deployment: "code",
    handler: "process.handler",
    connections: [queue], // Auto-configures event source mapping
  }),
);

ECS with Queue Access

const queue = app.addMessaging(
  MessagingFactory.build("WorkQueue", { type: "queue" }),
);

app.addCompute(
  ComputeFactory.build("Worker", {
    type: "ecs",
    services: [
      {
        name: "worker",
        capacityProvider: "FARGATE",
        containers: [
          {
            environment: {
              QUEUE_URL: queue.getQueueUrl(),
            },
          },
        ],
      },
    ],
    connections: [queue], // Grants send/receive permissions
  }),
);

Access Grants

Queue Permissions

// Send only
queue.grantSendMessages(producer);

// Receive and delete
queue.grantConsumeMessages(consumer);

// Purge the queue
queue.grantPurge(admin);

// Send and consume in one call
queue.grantFull(worker);

Topic Permissions

// Publish
topic.grantPublish(publisher);

// Subscribe (for service principals)
topic.grantSubscribe(subscriber);

Best Practices

  1. Use FIFO queues when order matters
  2. Always configure DLQs for production queues
  3. Set appropriate timeouts based on processing time
  4. Use topics for event broadcasting
  5. Use EventBridge for complex routing rules
  6. Monitor queue depth for scaling decisions

Next Steps

Compute Factory

Process messages with Lambda or ECS

Payload Pattern

See messaging in action with OpenNext