处理可见性超时与再次投递

AWSBeginner
立即练习

介绍

工作程序领取了订单任务,却在确认前停止。你将观察同一任务再次出现,为下一次投递提供更多处理时间,并在确认之前检查实际订单。

请先完成 使用 SQS 发送和消费任务。这个独立 VM 提供自己的工作程序、表和参考数据;不会复用之前的队列、消息或接收句柄。

准备一个用于再次投递的任务

本步骤中,创建默认可见性超时较短的队列,并发送一个任务,暂不处理它。

使用 Terminal 旁的 AWS View 对比当前队列、工作程序结果和存储的订单。保留无关的参考数据。

在准备好的项目目录中操作:

cd /home/labex/project

创建 Standard 队列。默认可见性超时为 30 秒,在领取请求没有指定覆盖值时使用。$(...) 保存选定的队列地址,供后续命令使用。

QUEUE_URL=$(aws sqs create-queue --queue-name labex-q02-jobs --attributes VisibilityTimeout=30 --query QueueUrl --output text)

发送一个 JSON 任务:

aws sqs send-message --queue-url "$QUEUE_URL" --message-body '{"id":"redelivery-order","quantity":3}'

读取默认超时和计数:

aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names VisibilityTimeout ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

预期超时为 30,一个消息可用,零个消息处于处理中。在 AWS View 中,任务领取次数为零,提供的 Lambda 没有执行记录,也没有存储的订单。发送只是将任务交给队列,不会处理它。

观察超时到期与第二次投递

本步骤中,领取任务,不确认它,并在可见性到期后观察第二次投递。

一条消息的两次投递

可见性到期后,同一条消息可以再次投递,并获得新的 receipt handle。

下面的命令块是一个有时间安排的实验。运行前先阅读它。第一次领取将可见性覆盖为 10 秒;紧接着的第二次领取应找不到消息,因为任务仍被隐藏。sleep 12 等待期限过去。最后一次领取为返回的任务设置 120 秒窗口,让你有时间检查,避免与短超时竞速。每个 > 将 JSON 响应保存到不同文件中。

aws sqs receive-message --queue-url "$QUEUE_URL" --max-number-of-messages 1 --visibility-timeout 10 --message-system-attribute-names ApproximateReceiveCount --output json > first-delivery.json
aws sqs receive-message --queue-url "$QUEUE_URL" --max-number-of-messages 1 --wait-time-seconds 0 --output json > while-hidden.json
sleep 12
aws sqs receive-message --queue-url "$QUEUE_URL" --max-number-of-messages 1 --visibility-timeout 120 --message-system-attribute-names ApproximateReceiveCount --output json > second-delivery.json

未领取到消息不会处理或删除任何内容。显示该响应:

cat while-hidden.json

预期响应为空,不包含 Messages。jq -s 将两份保存的响应一起读取:.[0] 是第一次投递,.[1] 是第二次投递。在不打印句柄的情况下,对比消息身份和投递句柄:

jq -s '{
  same_message: (.[0].Messages[0].MessageId == .[1].Messages[0].MessageId),
  new_receipt: (.[0].Messages[0].ReceiptHandle != .[1].Messages[0].ReceiptHandle),
  receive_count: .[1].Messages[0].Attributes.ApproximateReceiveCount
}' first-delivery.json second-delivery.json

预期 same_message 和 new_receipt 都为 true,领取次数为 "2"。消息 ID 在多次尝试之间标识同一条队列消息。接收句柄标识一次投递尝试,因此修改可见性和删除消息时,始终使用最新句柄。

AWS View 显示相同的正文处于处理中,已领取两次,但还没有订单。这是未确认尝试之后发生的实际再次投递,无需第二次发送。Standard 队列也可能因其他原因投递重复消息;可见性管理不能提供恰好一次处理保证。

AWS View 示例:同一任务第二次投递后处于处理中,但尚无存储的订单

这个实际示例展示业务处理前领取次数为二的状态。不同工作目录中的消息标识符会有所不同。

延长窗口并完成处理

本步骤中,延长当前投递的处理窗口,运行提供的工作程序,并只在验证存储数据之后确认消息。

从第二份响应中选择最新接收句柄。jq -r 输出适合作为命令参数的纯字符串。

RECEIPT_HANDLE=$(jq -r '.Messages[0].ReceiptHandle' second-delivery.json)

将这一次特定投递的可见性改为 300 秒:

aws sqs change-message-visibility --queue-url "$QUEUE_URL" --receipt-handle "$RECEIPT_HANDLE" --visibility-timeout 300

新的时间间隔从修改成功时开始。它不会改变队列默认的 30 秒设置,也不会确认任务。如果 120 秒检查窗口已到期,在修改可见性前再次领取任务并保存到 second-delivery.json,然后选择最新句柄。额外尝试会增加领取次数;如果需要重复精确的两次投递观察,请在全新工作环境中重新运行这个有时间安排的实验。

将领取的正文从 JSON 文本转换为任务对象:

jq '.Messages[0].Body | fromjson' second-delivery.json > job.json

运行提供的 Lambda,然后检查结果:

aws lambda invoke --function-name labex-q02-worker --payload fileb://job.json worker-response.json
cat worker-response.json

预期看到 processed: true、数量 3 和总金额 850 美分。独立读取持久化项目:

aws dynamodb get-item --table-name labex-q02-orders --key '{"id":{"S":"redelivery-order"}}' --consistent-read --query Item

只有确认实际存储结果后,才能使用当前接收句柄删除消息:

aws sqs delete-message --queue-url "$QUEUE_URL" --receipt-handle "$RECEIPT_HANDLE"
aws sqs get-queue-attributes --queue-url "$QUEUE_URL" --attribute-names VisibilityTimeout ApproximateNumberOfMessages ApproximateNumberOfMessagesNotVisible

预期默认超时为 30,可用消息和处理中的消息均为零。AWS View 显示空队列、实际工作程序输入和结果,以及订单 redelivery-order/3/850。延长可见性降低了本次尝试处理期间其他工作程序领取任务的可能性。它不会让业务操作具备幂等性;后续实验将教授防止重复效果的持久化保护。

移除队列和自己的结果

本步骤中,移除你的队列、订单和执行日志,同时保留提供的配套资源和参考数据。

aws sqs delete-queue --queue-url "$QUEUE_URL"
aws dynamodb delete-item --table-name labex-q02-orders --key '{"id":{"S":"redelivery-order"}}'
aws logs delete-log-group --log-group-name /aws/lambda/labex-q02-worker

通过成功的服务查询确认资源已不存在且参考资源仍然可用:

aws sqs list-queues
aws dynamodb scan --table-name labex-q02-orders --query Items
aws dynamodb scan --table-name labex-q02-reference --query Items

不再有队列 URL 或订单项目。参考项目仍包含 keep unchanged。AWS View 显示相同的清理状态,提供的工作程序仍然可用。网络或身份验证错误不能证明删除成功。

移除本地投递和响应文件:

rm -f first-delivery.json while-hidden.json second-delivery.json job.json worker-response.json

结束环境之前,运行本步骤的检查。

总结

你观察了未确认的 SQS 任务在可见性到期后重新变得可用,领取了具有新接收句柄和更高领取次数的同一消息,并延长了当前投递的处理时间。你在确认前验证了实际存储的订单,并清理自己的队列、结果和日志,同时保留提供的资源。