使用 EventBridge 路由订单事件

AWSBeginner
立即练习

介绍

履约系统需要新下单的订单,而账单和取消事件应交给其他系统。你将把匹配的事件路由到队列,并验证实际到达的是哪些消息。

请先完成 使用 SQS 发送和消费任务 和 使用资源策略保护存储桶。这个独立 VM 提供自己的 CLI 访问和参考数据;不会复用之前的队列或凭证。

相关认证考点

本实验为以下认证考点提供动手练习。

准备总线与目标队列

本步骤中,创建两个独立的位置:一个接收事件,一个保存匹配的任务等待消费者处理。

使用 Terminal 旁的 AWS View,将 CLI 查询与本实验的实际资源和结果对比。保留提供的参考数据。

Amazon EventBridge 路由描述已发生事情的事件。总线(bus)接收事件,规则(rule)匹配字段,目标(target)接收匹配的事件。自定义总线将本应用的事件与默认总线分离。SQS 队列保存投递,直到消费者处理它们。从项目目录开始。shell 赋值保存 CLI 返回的标识符;--query 选择所需字段,--output text 让下一条命令可以使用该值。

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)

总线响应包含其 ARN,QUEUE_URL 则在消息操作中标识队列。队列 ARN 在目标或权限策略中标识队列。这些标识符各有用途。

检查两个空资源:

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

尚无规则,队列中也没有可用或处理中的消息。AWS View 显示你的自定义总线和空队列。运行准备检查。

匹配订单并授权一条规则

本步骤中,将匹配规则连接到队列,并只授权该规则的投递。

生产者、总线、规则与队列

匹配规则选择事件;队列的来源规则授权独立地允许投递。

事件模式(event pattern)是对事件字段的过滤器。source 指定生产者,detail-type 指定事件类别。下面的每个数组列出接受的值。here-document 将 JSON 标记之间的字面 JSON 写入文件;为标记加引号可防止 shell 展开。file:// 告诉 CLI 读取该文件。

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)

规则已启用,但匹配本身不会授权投递。队列资源策略必须允许 EventBridge 服务发送消息,并通过 aws:SourceArn 将范围限定为这条规则。写入普通 JSON 策略;shell 会插入你的队列和规则 ARN。

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

属性 API 将策略存储为 JSON 字符串,因此 --rawfile 将该文档读入 Policy 属性。授权覆盖一个队列和一条来源规则。

目标是规则的目的地。它的 ID 让你可以在稍后更新或移除该连接:

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 为零,描述的规则具有预期模式,目标 ARN 等于你的队列。AWS View 此时显示规则及其队列目标。仍然没有可投递的事件。运行连接检查。

证明匹配与投递边界

本步骤中,发布匹配和无关事件,然后测试来源权限失败,确保没有新增队列消息。

EventBridge 事件具有路由字段和 detail 载荷。PutEvents API 接受 JSON 编码字符串形式的 Detail。写入三个易读的条目:一个下单事件、一个账单事件和一个取消事件。jq 将每个 Detail 对象转换为 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

发布响应报告零个失败条目,并为每个接受的条目返回事件 ID。只有 route-order 同时匹配两个字段,因此队列中有一条可用消息。AWS View 显示它的完整事件封装:来源、详情类型、账户、区域和详情。

读取消费者实际看到的正文。领取通常会在可见性超时期间隐藏消息;--visibility-timeout 0 让本次检查后的消息立即恢复可见。查询只打印 ID 和正文,不显示接收句柄。这次检查不会完成业务处理或确认消息。

fromjson 让每个 JSON 正文易于阅读,同时保留其 SQS 消息 ID。它只改变显示的输出。

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

正文中的 detail.id 等于 route-order,detail.quantity 等于 2。账单和取消条目没有到达此队列。

下面的示例展示已启用的匹配规则、其队列目标,以及实际完整订单事件,其中包含账户和区域。

AWS View 显示目标队列中匹配的订单事件

现在让队列策略指向不同的来源 ARN,同时保持规则和目标启用:

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 接受此事件,但规则缺少所需队列授权。原始消息仍是队列中唯一的事件;denied-order 不存在。诊断管道时,要区分事件被接受与目标投递。本练习不研究投递重试。

恢复预期授权并再次检查:

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)}]'

只有原始 route-order 存在。修正后的策略授权后续投递;本实验不依赖之前被拒绝的事件再次重试。运行路由检查。

移除事件管道

本步骤中,移除你的目标、规则、自定义总线和临时队列,同时保留无关资源。

删除规则之前,先移除目标。然后删除自定义总线和队列。删除队列会丢弃为路由检查保留的模拟事件;我们并未声称它产生了业务结果。

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"

成功的只读查询证明剩余资源状态:

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

只保留默认总线,其规则列表为空,队列 URL 已不存在,参考项目包含 keep unchanged。身份验证或网络错误不能证明删除成功。AWS View 显示空的自定义资源列表和保留的参考资源。

移除你创建的普通文件:

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

结束 VM 之前,运行清理检查。

总结

你创建了自定义 EventBridge 总线,匹配下单事件,并通过精确的来源规则授权连接队列目标。实际队列正文显示哪些事件到达了消费者,而来源被拒绝的测试区分了事件接受与投递。你移除了自己创建的资源,同时保留默认总线和参考数据。

下一个实验将事件封装转换为队列消费者需要的更小载荷。