What Is Amazon EventBridge?
Amazon EventBridge is a serverless event integration service from AWS. It allows applications, AWS services, and supported third-party systems to publish events and route them to interested consumers. Instead of making synchronous requests to every downstream service, a producer emits a business event such as order.created, payment.completed, or file.uploaded. EventBridge evaluates routing configuration and delivers matching events to their destinations.
EventBridge supports event buses, filtering, event transformation, retry policies, and integrations with services such as AWS Lambda, Amazon SQS, Amazon SNS, and Step Functions. It also provides EventBridge Pipes for point-to-point integrations and EventBridge Scheduler for time-based invocations. However, an event bus does not automatically guarantee successful business processing. Reliable architectures still need idempotent consumers, durable state changes, failure handling, and clear event contracts.
Table of Contents
- What Amazon EventBridge Provides
- How Amazon EventBridge Works
- EventBridge Integrations and Advanced Features
- Delivery Guarantees and Failure Handling
- Production Design Example: Order Event Distribution
- Ready-to-Use Example: EventBridge with Terraform and Python
- Security, Performance, and Production Operations
- Frequently Asked Questions
- Conclusion
What Amazon EventBridge Provides
EventBridge provides infrastructure for connecting independently deployed applications through events. A producer sends information about something that happened, and consumers decide which events are relevant to their responsibilities. This reduces direct coupling between services and supports architectures where components evolve and scale independently.
The value is not simply asynchronous execution. EventBridge also centralizes event routing and provides integrations with AWS services and external systems, reducing the need to build and maintain custom event-dispatching code.
Why Applications Use EventBridge
Consider an order service that needs to notify billing, inventory, analytics, and customer communications after creating an order. Calling all four systems synchronously increases latency and creates dependencies on their availability.
With an event-driven design, the order service publishes one event and downstream systems subscribe according to their needs.
- Decoupling: Producers do not need to know every consumer.
- Flexible routing: Events reach destinations according to configured conditions.
- Independent deployment: Consumers can change without requiring the publisher to deploy.
- AWS integration: Applications can react to supported events from AWS services.
- Cross-account integration: Events can connect workloads in separate AWS accounts with appropriate policies.
- Less routing code: Infrastructure manages much of the event filtering and delivery process.
The trade-off is eventual coordination. When components communicate asynchronously, the producer cannot assume every subscriber has completed its work by the time publication succeeds.
For the architectural principles behind this design, read Event-Driven Architecture in Distributed Systems.
EventBridge vs. SNS, SQS, and Kafka
These technologies overlap in some integrations, but their main abstractions differ.
| Technology | Main Role | Typical Use |
|---|---|---|
| Amazon EventBridge | Event routing and integration | Route business and AWS events to selected destinations |
| Amazon SNS | Publish/subscribe notifications | Fan out messages to subscribers |
| Amazon SQS | Durable message queues | Buffer asynchronous work for consumers |
| Apache Kafka | Distributed event streaming | Retained partitioned streams, offsets, stream processing |
EventBridge excels when an event needs to be routed by its contents, AWS integration is important, or different teams own independent consumers. SQS is valuable when workers need to pull and acknowledge jobs at a controlled rate.
They are often combined rather than treated as alternatives: EventBridge routes matching events into SQS queues, and workers consume those queues independently.
How Amazon EventBridge Works
EventBridge receives events from custom applications, AWS services, or supported third-party integrations. It then matches and routes those events according to the configuration of the selected event-bus model.
One important architectural detail is that EventBridge now has two custom event-bus models with different capabilities and infrastructure APIs. They should not be treated as identical.
Custom Event Bus vs. Classic Event Bus
The newer Custom Event Bus uses consumer-managed subscribers. Consumers define how their events are filtered, transformed, and delivered. The bus can retain events for a configured period and supports capabilities such as replay and ordering.
Custom Event Bus – Classic uses rules and targets configured by the bus owner. A rule matches an event pattern and sends matching events to one or more targets. This is also the model used by the traditional default event bus.
| Characteristic | Custom Event Bus | Custom Event Bus – Classic |
|---|---|---|
| Routing ownership | Consumer-managed subscribers | Bus-owner-managed rules and targets |
| Event retention | Configurable bus retention | Archives configured separately |
| Replay | Subscriber replay from retained events | Archive and replay capability |
| Ordering | Supported through ordering features | No general delivery ordering guarantee |
| Infrastructure model | EventBridge V2 resource model | Traditional AWS Events resources |
AWS recommends starting new applications with the Custom Event Bus model where its capabilities fit. The Classic model remains supported and is widely used in existing Terraform and CloudFormation configurations.
The ready-to-use implementation later in this article uses Classic rules because it demonstrates the familiar aws_cloudwatch_event_bus, aws_cloudwatch_event_rule, and aws_cloudwatch_event_target resources.
Events, Sources, and Detail Types
A Classic EventBridge custom event typically contains an envelope with fields describing its origin and business meaning.
{
"version": "0",
"id": "generated-by-eventbridge",
"source": "com.example.orders",
"detail-type": "OrderCreated",
"account": "123456789012",
"time": "2026-10-21T14:00:00Z",
"region": "us-west-2",
"resources": [],
"detail": {
"event_id": "evt-10042",
"schema_version": 1,
"tenant_id": "tenant-42",
"order_id": "order-9821",
"total_cents": 4999
}
}
The producer supplies fields such as Source, DetailType, and Detail through PutEvents. EventBridge adds envelope metadata such as the generated event ID.
For business idempotency, use an event ID from the application payload rather than assuming the EventBridge envelope ID remains stable when the same logical event is published again.
Event contracts should use meaningful source names, explicit detail types, and versioned payloads. Names such as OrderCreated or PaymentCompleted describe facts that happened, rather than instructions tied to one consumer.
Event Rules, Filtering, and Targets
In a Classic event bus, rules match incoming events using event patterns. Matching evaluates the selected fields, including supported nested fields within detail.
For example, the following pattern matches order-created events with a positive amount:
{
"source": ["com.example.orders"],
"detail-type": ["OrderCreated"],
"detail": {
"total_cents": [
{
"numeric": [">", 0]
}
]
}
}
A rule can target services such as SQS, Lambda, SNS, Step Functions, and other supported integrations. Different rules can match the same event and deliver it to independent destinations.
EventBridge also supports operators for filtering by prefixes, existence, numeric values, and other documented conditions. This is useful when routing requirements become more specific than simple event-type matching.
Input transformers can reshape the event before delivery. However, transformations should not hide changes to the underlying business contract. Consumers need to know which fields they receive and how those fields evolve.
EventBridge Integrations and Advanced Features
EventBridge is more than an event bus. Pipes and Scheduler solve related integration problems without requiring every workflow to use bus-based routing.
These capabilities should be selected according to whether the workload needs many-to-many event distribution, point-to-point processing, or time-based execution.
EventBridge Pipes
EventBridge Pipes connects one supported event source to one target. A pipe can optionally filter, transform, or enrich events during delivery.
For example, a pipe can connect DynamoDB Streams to an EventBridge bus or connect SQS to another supported processing destination.
Pipes are useful when the integration is fundamentally one-to-one and you do not need a general-purpose fan-out router for that step.
A typical flow includes:
- Read from a supported source.
- Apply an optional event filter.
- Invoke an optional enrichment step.
- Transform the event if required.
- Deliver the result to one configured target.
A pipe is not a substitute for durable business transaction coordination. If a database write and an external event publication must remain consistent, the application still needs an appropriate reliability pattern.
EventBridge Scheduler
EventBridge Scheduler runs operations at configured times. It supports one-time schedules, recurring schedules, cron expressions, rate expressions, time zones, and configurable delivery windows.
For example, Scheduler can invoke a Lambda function every morning, start an ECS task at a configured time, or send a message to SQS for later processing.
Unlike an event bus rule that reacts to an incoming event, Scheduler creates work because a scheduled time has arrived.
Use Scheduler for new time-based automation where its supported target and scheduling features are appropriate. It offers more scheduling-specific capabilities than legacy scheduled rules.
A scheduled invocation can still fail. Configure suitable retries, failure handling, and idempotency, especially when a delayed or repeated invocation could cause incorrect business effects.
Archives, Replay, and Schema Evolution
Event replay is useful when a consumer has been offline, a projection must be rebuilt, or a bug caused previously delivered events to be processed incorrectly.
The replay mechanism depends on the event-bus model. Custom Event Bus supports configurable retention and subscriber replay. Classic event buses support separately configured archives and replay operations.
Replay should be treated as a new processing attempt, not as a harmless read-only activity. A replayed order-created event could send a duplicate email or initiate another fulfillment action unless consumers are idempotent.
Event schemas also require deliberate evolution. Producers should avoid changing the meaning of existing fields, and consumers should tolerate explicitly supported versions rather than silently accepting incompatible payloads.
For a broader discussion of replay and consumer compatibility, read What Is Change Data Capture?.
Delivery Guarantees and Failure Handling
EventBridge can reliably route events, but successful publication, successful target delivery, and completed business processing are three separate milestones.
Understanding those boundaries prevents common mistakes such as reporting that an order has been fulfilled merely because its creation event was accepted by an event bus.
Retries and Dead-Letter Queues
For Classic rules, EventBridge supports configurable target delivery retries and dead-letter queues. Retry behavior depends on failure type and the selected target configuration.
Traditional Classic rule target delivery defaults to retrying for up to 24 hours and up to 185 attempts, with exponential backoff and jitter, subject to documented exceptions.
A rule target DLQ can capture events that EventBridge could not deliver successfully after the applicable retries. This is separate from a consumer processing DLQ.
- EventBridge target delivery failure: EventBridge cannot deliver an event to a destination.
- SQS consumer failure: EventBridge successfully delivers the event to SQS, but a worker fails after receiving it.
- Lambda business failure: A function receives an event but cannot complete its operation.
Each failure boundary needs its own recovery strategy. An SQS worker DLQ cannot recover an event that never reached the worker's source queue.
For practical recovery design, see Dead-Letter Queues, Retries, and Poison Messages.
Idempotency and Event Ordering
Classic EventBridge does not guarantee that events arrive at targets in publication order. Delivery retries, independent rules, and consumer-side processing can further change the order in which business effects occur.
For example, a consumer could receive an OrderCancelled event before it processes an earlier OrderCreated event.
A robust consumer can use entity versions, timestamps with appropriate concurrency checks, or explicit business-state transitions to reject stale updates.
At-least-once delivery also means that the same logical event may be processed more than once. Use a stable application event ID and enforce idempotency around operations that cannot safely repeat.
The newer Custom Event Bus supports ordering capabilities, but ordering must still be considered alongside the guarantees of downstream targets and applications. Broker-level ordering does not make a multi-service workflow an atomic transaction.
Reliable Event Publishing
Suppose an order service commits an order to PostgreSQL and then publishes an event. If the process crashes between the database commit and the publish call, the order exists but no event is distributed.
Reversing the operation is also unsafe: publishing first could allow consumers to react to an order that later fails to commit.
The transactional outbox pattern addresses this by recording the business change and an outgoing event in the same database transaction. A separate publisher delivers committed outbox records to EventBridge.
Even with an outbox, publishing may occur more than once if the publisher crashes after EventBridge accepts an event but before the publisher records completion. Consumers therefore still need idempotency.
See What Is a Transactional Outbox? for implementation details.
Production Design Example: Order Event Distribution
Consider a SaaS commerce platform with a FastAPI order service, PostgreSQL, billing, fulfillment, notifications, and analytics. Each downstream service needs a different subset of business events.
The system must support independent consumer failures without blocking checkout and must allow a new consumer to be added without modifying the order service.
Multi-Service Event Architecture
A production deployment can use:
- FastAPI order service: Validates requests and creates orders.
- PostgreSQL and outbox table: Atomically store business records and outgoing events.
- Outbox publisher: Publishes committed events to EventBridge.
- EventBridge bus: Routes events according to source, type, tenant, and other supported fields.
- Fulfillment SQS queue: Buffers order-created events for warehouse processing.
- Notification SQS queue: Buffers events that require customer communication.
- Analytics processing: Builds reporting projections from relevant events.
- Delivery DLQs: Capture failed EventBridge target deliveries.
- Consumer DLQs: Capture events that reached workers but could not be processed.
A fulfillment rule might match only OrderCreated, while a notification rule could match OrderCreated and OrderShipped.
For a multitenant platform, routing can also use fields within detail, such as tenant category or region. However, EventBridge filtering is not a replacement for authorization or tenant isolation.
Each queue should have its own retry policy and concurrency limits. Analytics workers can fall behind without preventing fulfillment workers from completing their jobs.
Failure Scenarios and Recovery
Suppose the fulfillment queue policy is accidentally changed and EventBridge can no longer send messages to it. Other matching targets may continue receiving events while fulfillment delivery fails.
A rule target DLQ captures relevant failed deliveries for investigation. After fixing permissions, operators can replay or republish the retained events through a controlled procedure.
Another failure occurs when a fulfillment worker updates its database and crashes before acknowledging the SQS message. The queue may deliver the event again, so fulfillment must recognize the stable event ID and avoid creating a second shipment.
Recovery procedures should distinguish between delivery failures, consumer failures, and incomplete business workflows. Treating all three as the same incident can lead to unsafe or incomplete replay.
Ready-to-Use Example: EventBridge with Terraform and Python
This implementation creates a Classic custom event bus with two rules, each delivering matching events to its own Amazon SQS queue. A third queue acts as a dead-letter destination for EventBridge target delivery failures.
The notification queue receives only OrderCreated events. The analytics queue receives both OrderCreated and OrderCancelled events. A Python publisher sends test events, and a Python consumer reads and acknowledges the routed messages.
1. Project Structure
Install Terraform, Python 3, and the AWS CLI. Configure credentials with permissions to create EventBridge rules, SQS queues, and resource policies, and to publish and consume messages.
Create the following files:
eventbridge-demo/
main.tf
outputs.tf
requirements.txt
publisher.py
consumer.py
The example uses a single AWS account and the us-west-2 Region. It provisions billable resources, so use a development account or disposable environment.
2. Provision the Event Bus and Queues
Create main.tf:
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = "us-west-2"
}
# -----------------------------------
# Classic custom event bus
# -----------------------------------
resource "aws_cloudwatch_event_bus" "orders" {
name = "sysdespro-orders-demo"
}
# -----------------------------------
# Destination queues
# -----------------------------------
resource "aws_sqs_queue" "notifications" {
name = "sysdespro-events-notifications"
sqs_managed_sse_enabled = true
receive_wait_time_seconds = 20
}
resource "aws_sqs_queue" "analytics" {
name = "sysdespro-events-analytics"
sqs_managed_sse_enabled = true
receive_wait_time_seconds = 20
}
# EventBridge target delivery failures.
resource "aws_sqs_queue" "delivery_dlq" {
name = "sysdespro-events-delivery-dlq"
sqs_managed_sse_enabled = true
message_retention_seconds = 1209600
}
# -----------------------------------
# Independent routing rules
# -----------------------------------
resource "aws_cloudwatch_event_rule" "notifications" {
name = "sysdespro-notification-events"
event_bus_name = aws_cloudwatch_event_bus.orders.name
event_pattern = jsonencode({
source = ["com.sysdespro.orders"]
"detail-type" = ["OrderCreated"]
})
}
resource "aws_cloudwatch_event_rule" "analytics" {
name = "sysdespro-analytics-events"
event_bus_name = aws_cloudwatch_event_bus.orders.name
event_pattern = jsonencode({
source = ["com.sysdespro.orders"]
"detail-type" = [
"OrderCreated",
"OrderCancelled"
]
})
}
# -----------------------------------
# Destination queue permissions
# -----------------------------------
resource "aws_sqs_queue_policy" "notifications" {
queue_url = aws_sqs_queue.notifications.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "events.amazonaws.com"
}
Action = "sqs:SendMessage"
Resource = aws_sqs_queue.notifications.arn
Condition = {
ArnEquals = {
"aws:SourceArn" = aws_cloudwatch_event_rule.notifications.arn
}
}
}]
})
}
resource "aws_sqs_queue_policy" "analytics" {
queue_url = aws_sqs_queue.analytics.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "events.amazonaws.com"
}
Action = "sqs:SendMessage"
Resource = aws_sqs_queue.analytics.arn
Condition = {
ArnEquals = {
"aws:SourceArn" = aws_cloudwatch_event_rule.analytics.arn
}
}
}]
})
}
# Both rules may send failed deliveries to this DLQ.
resource "aws_sqs_queue_policy" "delivery_dlq" {
queue_url = aws_sqs_queue.delivery_dlq.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
Service = "events.amazonaws.com"
}
Action = "sqs:SendMessage"
Resource = aws_sqs_queue.delivery_dlq.arn
Condition = {
ArnEquals = {
"aws:SourceArn" = [
aws_cloudwatch_event_rule.notifications.arn,
aws_cloudwatch_event_rule.analytics.arn
]
}
}
}]
})
}
# -----------------------------------
# EventBridge targets and retries
# -----------------------------------
resource "aws_cloudwatch_event_target" "notifications" {
event_bus_name = aws_cloudwatch_event_bus.orders.name
rule = aws_cloudwatch_event_rule.notifications.name
arn = aws_sqs_queue.notifications.arn
retry_policy {
maximum_retry_attempts = 10
maximum_event_age_in_seconds = 3600
}
dead_letter_config {
arn = aws_sqs_queue.delivery_dlq.arn
}
depends_on = [
aws_sqs_queue_policy.notifications,
aws_sqs_queue_policy.delivery_dlq
]
}
resource "aws_cloudwatch_event_target" "analytics" {
event_bus_name = aws_cloudwatch_event_bus.orders.name
rule = aws_cloudwatch_event_rule.analytics.name
arn = aws_sqs_queue.analytics.arn
retry_policy {
maximum_retry_attempts = 10
maximum_event_age_in_seconds = 3600
}
dead_letter_config {
arn = aws_sqs_queue.delivery_dlq.arn
}
depends_on = [
aws_sqs_queue_policy.analytics,
aws_sqs_queue_policy.delivery_dlq
]
}
The rules route events according to their source and detail type. The notification rule matches only OrderCreated, while analytics matches both supported event types.
The SQS queue policies permit the EventBridge service principal to deliver messages, restricted to the corresponding rule ARNs. Each target has bounded retries and a DLQ for failed EventBridge deliveries.
This demonstration does not configure SQS consumer-processing DLQs. In production, configure those separately if worker failures also require isolation and recovery.
Create outputs.tf:
output "event_bus_name" {
value = aws_cloudwatch_event_bus.orders.name
}
output "notification_queue_url" {
value = aws_sqs_queue.notifications.id
}
output "analytics_queue_url" {
value = aws_sqs_queue.analytics.id
}
output "delivery_dlq_url" {
value = aws_sqs_queue.delivery_dlq.id
}
3. Publish Events with Python
Create requirements.txt:
boto3
Create publisher.py:
import json
import os
import uuid
from datetime import datetime, timezone
import boto3
from botocore.config import Config
BUS_NAME = os.environ["EVENT_BUS_NAME"]
REGION = os.getenv("AWS_REGION", "us-west-2")
events = boto3.client(
"events",
region_name=REGION,
config=Config(
retries={
"mode": "standard",
"max_attempts": 5,
}
),
)
def publish_order_event(
order_id: str,
event_type: str,
event_id: str,
) -> str:
if event_type not in {
"OrderCreated",
"OrderCancelled",
}:
raise ValueError("Unsupported event type")
detail = {
"event_id": event_id,
"schema_version": 1,
"order_id": order_id,
"created_at": datetime.now(
timezone.utc
).isoformat(),
}
response = events.put_events(
Entries=[
{
"EventBusName": BUS_NAME,
"Source": "com.sysdespro.orders",
"DetailType": event_type,
"Detail": json.dumps(detail),
}
]
)
# PutEvents can partially fail while the
# API call itself returns successfully.
if response["FailedEntryCount"]:
failure = response["Entries"][0]
raise RuntimeError(
f"Event publish failed: {failure}"
)
return response["Entries"][0]["EventId"]
def main():
created_id = publish_order_event(
order_id="order-1001",
event_type="OrderCreated",
event_id=str(uuid.uuid4()),
)
cancelled_id = publish_order_event(
order_id="order-1002",
event_type="OrderCancelled",
event_id=str(uuid.uuid4()),
)
print("Created EventBridge ID:", created_id)
print("Cancelled EventBridge ID:", cancelled_id)
if __name__ == "__main__":
main()
The script publishes two events and checks the individual entry results. This check matters because a successful HTTP response from PutEvents does not guarantee every entry in a batch succeeded.
The example generates one business event ID per published event. A real outbox publisher should preserve the same business event ID when retrying an ambiguous publication attempt.
The PutEvents operation shown here is part of the Classic EventBridge programming model. Applications using the newer Custom Event Bus must follow its supported publishing APIs and event schema.
4. Consume Routed Events
Create consumer.py:
import json
import logging
import os
import signal
import time
import boto3
from botocore.config import Config
QUEUE_URL = os.environ["SQS_QUEUE_URL"]
REGION = os.getenv("AWS_REGION", "us-west-2")
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
logger = logging.getLogger(__name__)
running = True
sqs = boto3.client(
"sqs",
region_name=REGION,
config=Config(
connect_timeout=5,
read_timeout=30,
retries={
"mode": "standard",
"max_attempts": 5,
},
),
)
def shutdown(signum, frame):
global running
running = False
signal.signal(signal.SIGTERM, shutdown)
signal.signal(signal.SIGINT, shutdown)
def process_event(event: dict) -> None:
if event.get("source") != "com.sysdespro.orders":
raise ValueError("Unexpected event source")
detail = event.get("detail")
if not isinstance(detail, dict):
raise ValueError("Missing event detail")
if detail.get("schema_version") != 1:
raise ValueError("Unsupported schema version")
event_id = detail.get("event_id")
order_id = detail.get("order_id")
if not all(
isinstance(value, str) and value
for value in (event_id, order_id)
):
raise ValueError("Invalid event identifiers")
logger.info(
"Processing event=%s type=%s order=%s",
event_id,
event["detail-type"],
order_id,
)
# Real business side effects should use
# durable, atomic idempotency protection.
def consume_once() -> None:
response = sqs.receive_message(
QueueUrl=QUEUE_URL,
WaitTimeSeconds=20,
MaxNumberOfMessages=10,
)
for message in response.get("Messages", []):
message_id = message["MessageId"]
try:
event = json.loads(message["Body"])
if not isinstance(event, dict):
raise ValueError("Invalid event body")
process_event(event)
# Acknowledge only after success.
sqs.delete_message(
QueueUrl=QUEUE_URL,
ReceiptHandle=message["ReceiptHandle"],
)
except Exception:
logger.exception(
"Failed to process message=%s",
message_id,
)
def main():
logger.info("Starting EventBridge SQS consumer")
while running:
try:
consume_once()
except Exception:
logger.exception("SQS polling failed")
time.sleep(2)
logger.info("Consumer stopped")
if __name__ == "__main__":
main()
Classic EventBridge sends its event envelope to the SQS queue. The consumer extracts the business payload from detail and deletes messages only after successfully validating and processing them.
This worker demonstrates transport acknowledgment, not durable business idempotency. A production worker should record successful event processing in an appropriate data store and prevent repeated side effects when the same logical event is redelivered.
5. Deploy, Verify, and Clean Up
Run Terraform to create the event bus, rules, queues, permissions, and targets:
# Initialize and validate infrastructure.
terraform init
terraform fmt
terraform validate
# Review planned changes.
terraform plan
# Create the EventBridge resources.
terraform apply
# Configure the publisher.
export AWS_REGION="us-west-2"
export EVENT_BUS_NAME="$(terraform output -raw event_bus_name)"
# Install the Python dependency.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Publish test events.
python publisher.py
# Consume notification events.
export SQS_QUEUE_URL="$(
terraform output -raw notification_queue_url
)"
python consumer.py
The notification queue should receive only OrderCreated messages. Stop the consumer using Ctrl+C and run it again with the analytics queue URL.
# Switch to the analytics queue.
export SQS_QUEUE_URL="$(
terraform output -raw analytics_queue_url
)"
python consumer.py
# Inspect approximate queue depth.
aws sqs get-queue-attributes \
--queue-url "$SQS_QUEUE_URL" \
--attribute-names \
ApproximateNumberOfMessages \
ApproximateNumberOfMessagesNotVisible
# Inspect the EventBridge delivery DLQ.
DLQ_URL="$(terraform output -raw delivery_dlq_url)"
aws sqs get-queue-attributes \
--queue-url "$DLQ_URL" \
--attribute-names ApproximateNumberOfMessages
# Remove the disposable infrastructure.
terraform destroy
The analytics queue should contain both published event types. SQS metrics are approximate and may not reflect every change immediately.
For a delivery failure test, use a disposable setup and deliberately remove the relevant queue permission, then publish another matching event. Restore the policy and inspect the target's delivery failure metrics and DLQ as appropriate. Do not disrupt production resource policies merely to test this behavior.
Destroying the demonstration queues permanently removes their remaining messages. Do not use this cleanup procedure for important retained business events.
Security, Performance, and Production Operations
EventBridge simplifies routing, but a production event bus is also a shared integration boundary. Its resource policies, event naming conventions, quotas, and monitoring affect every application that publishes or consumes events.
Reliable operation requires visibility into both EventBridge routing and downstream processing, because successful delivery to a target does not establish successful completion by that target's application.
IAM, Resource Policies, and Cross-Account Routing
Publishing to a Classic custom event bus typically requires events:PutEvents permission on the target bus. Limit this permission to authorized producer roles and specific resources.
Event bus resource policies can support cross-account access. When integrating accounts, apply least privilege to the allowed principals and use supported event-source restrictions where appropriate.
For target delivery, permissions vary by destination. SQS and SNS integrations commonly use resource policies, while some other target types require an execution role.
Security practices include:
- Use narrowly scoped IAM policies for publishers.
- Restrict cross-account event publication.
- Validate the business event source and schema in consumers.
- Avoid including secrets or unnecessary personal data in event payloads.
- Protect encrypted destinations with correct KMS permissions.
- Review rule and subscriber changes through infrastructure code and deployment approvals.
- Guard against routing loops when forwarding events between buses.
An event bus is not an authorization system for individual tenants. Publishing an event with a tenant_id does not prove the publisher is authorized to act on that tenant's behalf.
Monitoring and Pricing
EventBridge charges depend on the capabilities used, such as event ingestion, delivery, archives, replay, Pipes, Scheduler, and other applicable features. Pricing and quotas vary by event-bus model and Region.
Routing an event to several destinations may create additional billable delivery activity and downstream resource usage.
Operational monitoring should track:
- Published events: Volume accepted by the bus.
- Matched events: Events selected by routing rules or subscribers.
- Successful target invocations: EventBridge delivery outcomes.
- Failed target invocations: Routing or target delivery problems.
- Throttling: Requests or delivery activity exceeding applicable quotas.
- DLQ depth: Failed deliveries requiring investigation.
- Downstream queue age: Delay between successful delivery and business processing.
- Consumer error rate: Failures after events reach their intended destination.
Use application event IDs to correlate logs across the publisher, EventBridge delivery, queues, and downstream workers. Without correlation identifiers, asynchronous incidents can be difficult to investigate.
Common Mistakes
Several mistakes appear frequently in EventBridge systems:
- Confusing Classic and Custom Event Bus APIs: Infrastructure or clients are configured for the wrong event-bus model.
- Assuming events arrive in order: Consumers apply stale changes after newer ones.
- Ignoring partial PutEvents failures: Some events are not accepted even though the API request returned successfully.
- Assuming target delivery means processing completed: Failed business operations remain unnoticed.
- Omitting DLQs: Delivery failures are not retained for investigation.
- Using unstable event identifiers: Repeated publication creates duplicate business operations.
- Publishing directly after database commits: Process crashes can leave data without corresponding events.
- Creating overly broad event patterns: Unrelated consumers receive unexpected events.
- Breaking event schemas: Existing subscribers cannot process newer event versions.
- Forgetting downstream backpressure: Event delivery outpaces consumer capacity.
- Building circular bus routing: Events repeatedly trigger more events and unnecessary processing.
Production Checklist
Before introducing EventBridge into a critical application, verify that:
- The selected event-bus model matches current AWS capabilities and requirements.
- Business events have stable IDs, clear sources, and versioned schemas.
- Publishers verify individual publish results.
- Database changes and event publishing have a reliable consistency strategy.
- Routing rules are tested with matching and nonmatching events.
- Every required destination has the correct IAM or resource policy.
- Retries have appropriate limits and failure destinations.
- Consumers handle duplicates and unsupported payloads safely.
- Ordering assumptions are explicit and enforced where necessary.
- Replay does not repeat irreversible business side effects.
- Cross-account access and encryption are reviewed.
- Published, matched, failed, and processed event metrics are monitored.
- Downstream queue capacity and worker concurrency are managed.
Frequently Asked Questions
EventBridge combines several event integration features, so it is important to distinguish event routing from durable queue processing, scheduled execution, and complete workflow orchestration.
What Is Amazon EventBridge Used For?
Amazon EventBridge is used to connect applications and AWS services through events. Common use cases include microservice integration, event-driven workflows, AWS infrastructure automation, external SaaS integrations, and routing business events to queues or functions.
What Is the Difference Between EventBridge and SNS?
SNS primarily distributes messages to subscribers using publish/subscribe topics. EventBridge provides event-based routing and integration capabilities, including filtering, transformation, and supported AWS service integrations.
Both can fan out events, but the most appropriate choice depends on routing complexity, endpoint requirements, ordering, retention, and the broader application architecture.
Can EventBridge Replace SQS?
EventBridge can route events directly to supported targets, but it does not replace SQS's competing-consumer queue model for every workload.
When workers need to control message consumption, visibility timeouts, acknowledgments, and queue backlog independently, SQS remains valuable. A common design routes EventBridge events into separate SQS queues.
Does EventBridge Guarantee Exactly-Once Delivery?
Classic EventBridge delivery does not provide a general exactly-once business-processing guarantee. Events may be delivered more than once, and application consumers must account for retries and duplicate side effects.
The newer Custom Event Bus has additional delivery and ordering capabilities, but applications must still examine the complete processing path rather than relying solely on broker-level guarantees.
Does EventBridge Preserve Event Order?
Classic EventBridge does not guarantee delivery ordering. The newer Custom Event Bus supports ordered delivery with the appropriate configuration and constraints.
Downstream queues, workers, and databases may introduce additional ordering considerations, so end-to-end business ordering must be designed explicitly.
Can EventBridge Run Scheduled Jobs?
Yes. EventBridge Scheduler supports one-time and recurring schedules, time zones, and configurable delivery windows. It can invoke supported AWS targets, including Lambda functions and SQS queues.
For new scheduling workloads, Scheduler is generally preferable to legacy scheduled rules when its supported capabilities meet the requirements.
Is Amazon EventBridge Free?
AWS provides applicable Free Tier allowances or credits for certain workloads and eligible accounts. Beyond those allowances, costs depend on event ingestion, delivery, retention, replay, Pipes, Scheduler, and related resources.
Check the current pricing for the selected EventBridge model and Region, including the costs of downstream SQS, Lambda, and other AWS services.
Conclusion
Amazon EventBridge is a serverless service for connecting applications through events. It enables producers to publish business changes without knowing every downstream consumer, while routing configuration determines which destinations receive those events.
Its event-bus models support different approaches to routing ownership and retention. EventBridge Pipes handles point-to-point integrations, and EventBridge Scheduler handles time-based operations. Together, these features reduce the amount of custom integration infrastructure teams need to maintain.
Production reliability still depends on well-defined event contracts, publisher consistency, retries, dead-letter queues, idempotent consumers, secure permissions, and monitoring. EventBridge manages event distribution; each application remains responsible for processing events correctly.
Key Takeaway: Use Amazon EventBridge when independently deployed systems need flexible event routing and AWS-native integrations. Choose the appropriate event-bus model, publish stable versioned events, and design the complete delivery and processing path for failures and duplicates.
More Articles to Read
Continue exploring these additional system design concepts related to message delivery, workflow coordination, background processing, and distributed system reliability.
Comments (0)