Route Order Events with EventBridge

AWSBeginner
Practice Now

Introduction

Fulfillment needs newly placed orders, while billing and cancellation events belong elsewhere. You will route matching events to a queue and verify which messages actually arrive.

Complete Send and Consume Jobs with SQS and Protect a Bucket with a Resource Policy first. This independent VM supplies its own CLI access and reference data; earlier queues and credentials are not reused.

Certification Relevance

This lab provides hands-on practice for the following exam topics.

Prepare a Bus and Destination Queue

In this step, create the independent places where events enter and matching work waits for a consumer.

Use AWS View beside Terminal to compare the CLI queries with this lab’s actual resources and results. Preserve the supplied reference data.

Amazon EventBridge routes events describing things that happened. A bus receives events, a rule matches fields, and a target receives matching events. A custom bus separates this application's events from the default bus. An SQS queue holds deliveries until a consumer processes them. Start in the project directory. Shell assignments save identifiers returned by the CLI; --query selects the needed field and --output text makes it usable by the next command.

cd /home/labex/project
BUS_NAME=labex-ev01-bus
RULE_NAME=labex-ev01-orders
aws events create-event-bus --name "$BUS_NAME"
QUEUE_URL=$(aws sqs create-queue \
  --queue-name labex-ev01-jobs \
  --query QueueUrl \
  --output text)
QUEUE_ARN=$(aws sqs get-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attribute-names QueueArn \
  --query Attributes.QueueArn \
  --output text)

The bus response contains its ARN, and QUEUE_URL identifies the queue for message operations. The queue ARN identifies it in a target or permission policy. These identifiers serve different purposes.

Inspect both empty resources:

aws events list-rules --event-bus-name "$BUS_NAME"
aws sqs get-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

There are no rules yet, and the queue has no available or in-flight messages. AWS View shows your custom bus and empty queue. Run the preparation check.

Match Orders and Authorize One Rule

In this step, connect a matching rule to the queue and authorize only that rule's deliveries.

producer bus rule queue

A matching rule selects the event; the queue’s source-rule grant separately permits its delivery.

An event pattern is a filter over event fields. source names the producer, while detail-type names the event category. Each array below lists accepted values. A here-document writes the literal JSON between JSON markers; quoting the marker prevents shell expansion. file:// tells the CLI to read that file.

cat > order-pattern.json <<'JSON'
{"source":["labex.orders"],"detail-type":["OrderPlaced"]}
JSON
RULE_ARN=$(aws events put-rule \
  --name "$RULE_NAME" \
  --event-bus-name "$BUS_NAME" \
  --event-pattern file://order-pattern.json \
  --state ENABLED \
  --query RuleArn \
  --output text)

The rule is enabled, but a match alone does not authorize delivery. The queue's resource policy must allow the EventBridge service to send, scoped by aws:SourceArn to this rule. Write an ordinary JSON policy; the shell inserts your queue and rule ARNs.

cat > queue-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sqs:SendMessage",
      "Resource": "$QUEUE_ARN",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "$RULE_ARN"
        }
      }
    }
  ]
}
EOF
jq -n --rawfile policy queue-policy.json '{Policy:$policy}' > queue-attributes.json
aws sqs set-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attributes file://queue-attributes.json

The attributes API stores the policy as a JSON string, so --rawfile reads that document into the Policy attribute. The grant covers one queue and one originating rule.

A target is the rule's destination. Its ID lets you update or remove that connection later:

cat > targets.json <<EOF
[
  {
    "Id": "order-queue",
    "Arn": "$QUEUE_ARN"
  }
]
EOF
aws events put-targets \
  --rule "$RULE_NAME" \
  --event-bus-name "$BUS_NAME" \
  --targets file://targets.json
aws events describe-rule --name "$RULE_NAME" --event-bus-name "$BUS_NAME"
aws events list-targets-by-rule --rule "$RULE_NAME" --event-bus-name "$BUS_NAME"

FailedEntryCount is zero for the target configuration, the described rule has the intended pattern, and the target ARN equals your queue. AWS View now shows the rule and its queue destination. There is still no event to deliver. Run the connection check.

Prove Matching and Delivery Boundaries

In this step, publish matching and unrelated events, then test a source-permission failure without adding a new queue message.

An EventBridge event has routing fields and a detail payload. The PutEvents API accepts Detail as a JSON-encoded string. Write three readable entries: one placed order, one billing event and one cancellation. jq converts each Detail object into the string required by the API.

cat > event-inputs.json <<EOF
[
  {
    "EventBusName": "$BUS_NAME",
    "Source": "labex.orders",
    "DetailType": "OrderPlaced",
    "Detail": {
      "id": "route-order",
      "quantity": 2
    }
  },
  {
    "EventBusName": "$BUS_NAME",
    "Source": "labex.billing",
    "DetailType": "OrderPlaced",
    "Detail": {
      "id": "billing-event",
      "quantity": 9
    }
  },
  {
    "EventBusName": "$BUS_NAME",
    "Source": "labex.orders",
    "DetailType": "OrderCancelled",
    "Detail": {
      "id": "cancelled-event",
      "quantity": 1
    }
  }
]
EOF
jq 'map(.Detail |= tojson)' event-inputs.json > events.json
aws events put-events --entries file://events.json
aws sqs get-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

The publish response reports zero failed entries and an event ID for each accepted entry. Only route-order matches both fields, so the queue contains one available message. AWS View shows its full event envelope: source, detail type, account, region and detail.

Read the actual consumer-visible body. Receiving normally hides a message for its visibility timeout; --visibility-timeout 0 makes this inspection visible again immediately. The query prints only its ID and body, keeping the receipt handle out of the display. This inspection does not complete business processing or acknowledge the message.

fromjson makes each JSON body readable while retaining its SQS message ID. It changes only the displayed output.

aws sqs receive-message \
  --queue-url "$QUEUE_URL" \
  --max-number-of-messages 10 \
  --visibility-timeout 0 \
  --output json | jq '[.Messages[] | {MessageId, Body: (.Body | fromjson)}]'

The body has detail.id equal to route-order and detail.quantity equal to 2. The billing and cancellation entries did not reach this queue.

The example below shows the enabled matching rule, its queue target and the actual complete order event, including the account and region.

AWS View shows the matching order event in the destination queue

Now point the queue policy at a different source ARN while keeping the rule and target enabled:

jq --arg wrong "${RULE_ARN}-other" '.Statement[0].Condition.ArnEquals["aws:SourceArn"]=$wrong' queue-policy.json > wrong-source-policy.json
jq -n --rawfile policy wrong-source-policy.json '{Policy:$policy}' > wrong-source-attributes.json
aws sqs set-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attributes file://wrong-source-attributes.json
cat > event-inputs.json <<EOF
[
  {
    "EventBusName": "$BUS_NAME",
    "Source": "labex.orders",
    "DetailType": "OrderPlaced",
    "Detail": {
      "id": "denied-order",
      "quantity": 4
    }
  }
]
EOF
jq 'map(.Detail |= tojson)' event-inputs.json > denied-event.json
aws events put-events --entries file://denied-event.json
aws sqs get-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attribute-names ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

EventBridge accepts this event, but the rule lacks the required queue grant. The original message remains the only queued event; denied-order is absent. Distinguish event acceptance from target delivery when diagnosing a pipeline. This exercise does not examine delivery retries.

Restore the intended grant and inspect again:

aws sqs set-queue-attributes \
  --queue-url "$QUEUE_URL" \
  --attributes file://queue-attributes.json
aws sqs receive-message \
  --queue-url "$QUEUE_URL" \
  --max-number-of-messages 10 \
  --visibility-timeout 0 \
  --output json | jq '[.Messages[] | {MessageId, Body: (.Body | fromjson)}]'

Only the original route-order is present. The corrected policy authorizes subsequent deliveries; this lab does not depend on an earlier denied event being retried. Run the routing check.

Remove the Event Pipeline

In this step, remove your target, rule, custom bus and disposable queue while preserving unrelated resources.

Remove the target before deleting its rule. Then delete the custom bus and queue. Queue deletion discards the synthetic event retained for routing inspection; no business result was claimed for it.

aws events remove-targets \
  --rule "$RULE_NAME" \
  --event-bus-name "$BUS_NAME" \
  --ids order-queue
aws events delete-rule --name "$RULE_NAME" --event-bus-name "$BUS_NAME"
aws events delete-event-bus --name "$BUS_NAME"
aws sqs delete-queue --queue-url "$QUEUE_URL"

Successful read-only queries establish what remains:

aws events list-event-buses
aws events list-rules --event-bus-name default
aws sqs list-queues
aws dynamodb scan --table-name labex-ev01-reference --query Items

Only the default bus remains, its rule list is empty, queue URLs are absent, and the reference item says keep unchanged. Authentication or network errors do not establish deletion. AWS View shows the empty custom-resource lists and preserved reference.

Remove the ordinary files you created:

rm -f event-inputs.json order-pattern.json queue-policy.json queue-attributes.json targets.json events.json wrong-source-policy.json wrong-source-attributes.json denied-event.json

Run the cleanup check before ending the VM.

Summary

You created a custom EventBridge bus, matched order-placement events and connected a queue target with an exact source-rule grant. Actual queue bodies showed which events reached the consumer, and the denied-source test separated event acceptance from delivery. You removed owned resources while preserving the default bus and reference data.

The next unit transforms an event envelope into the smaller payload a queue consumer needs.