可視性タイムアウトと再配信を扱う

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 ジョブを 1 件送ります。

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、利用可能なメッセージは 1 件、処理中のメッセージは 0 件となるはずです。AWS View では、ジョブの受信回数は 0 で、提供された Lambda には実行がなく、保存された注文もありません。送信はジョブをキューに受け付けるものであり、処理するものではありません。

期限切れと 2 回目の配信を観察する

このステップでは、ジョブを受信し、処理済みとして確認しないままにして、可視性の期限切れ後に 2 回目の配信を観察します。

1 つのメッセージと 2 回の配信

可視性が期限切れになると、同じメッセージが新しいレシートハンドルで再び配信される場合があります。

以下のコマンドブロックは、時間を決めて行う 1 つの実験です。実行前に読んでください。最初の受信は、可視性を 10 秒に上書きします。直後の 2 回目の受信では、そのジョブが非表示のため、何も見つからないはずです。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 は、保存した 2 つのレスポンスを一緒に読み取ります。.[0] は最初の配信、.[1] は 2 回目の配信です。ハンドルを表示せずに、メッセージの識別情報と配信のレシートを比較します。

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 は、試行をまたいでキュー内のメッセージを識別します。レシートハンドルは 1 回の配信試行を識別するため、可視性の変更と削除には常に最新のハンドルを使ってください。

AWS View には、同じ本文が処理中として表示され、受信回数は 2 回、注文はまだありません。これは、処理済みとして確認されなかった試行に続く実際の再配信です。2 回目の送信は不要でした。Standard キューは、他の理由でも重複配信する場合があります。可視性の管理は、厳密に 1 回の処理を提供しません。

AWS View の例:同じジョブが 2 回目の配信後に処理中で、保存された注文はまだない

この実際の例は、業務処理前の受信回数 2 を示します。メッセージ識別子は作業ディレクトリごとに異なります。

処理時間を延長して作業を完了する

このステップでは、現在の配信の処理時間を延長し、提供されたワーカーを完了させ、保存データを確認した後にだけ処理済みとして確認します。

2 回目のレスポンスから最新のレシートハンドルを選択します。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 に受信し、最新のハンドルを選択してください。追加の試行は受信回数を増やします。正確に 2 回の配信の観察を繰り返す必要がある場合は、新しい作業環境で時間を決めた実験を再実行してください。

受信した本文を 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、利用可能なメッセージも処理中のメッセージも 0 件となるはずです。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 ジョブが可視性の期限切れ後に利用可能になることを観察し、同じメッセージを新しいレシートハンドルと増えた受信回数で受信して、現在の配信の処理時間を延長しました。処理済みとして確認する前に実際の保存された注文を確認し、提供されたリソースを保持しながら、自分のキュー、結果、ログを後片付けしました。