SQS: replay DLQ messages back to source
The 'I deployed a fix, now reprocess every failure' one-liner. Drains a dead-letter queue and re-sends each body to the source queue.
Setup
- → brew install awscli
- → aws configure
Cost per run
free
The one-liner
$ DLQ="https://sqs.eu-west-1.amazonaws.com/123/my-dlq"
SRC="https://sqs.eu-west-1.amazonaws.com/123/my-queue"
while MSGS=$(aws sqs receive-message --queue-url "$DLQ" \
--max-number-of-messages 10 --wait-time-seconds 5) \
&& echo "$MSGS" | jq -e '.Messages | length > 0' >/dev/null; do
echo "$MSGS" | jq -c '.Messages[]?' | while read -r M; do
BODY=$(echo "$M" | jq -r .Body)
RH=$(echo "$M" | jq -r .ReceiptHandle)
aws sqs send-message --queue-url "$SRC" --message-body "$BODY" >/dev/null \
&& aws sqs delete-message --queue-url "$DLQ" --receipt-handle "$RH" >/dev/null
done
doneWhat each stage does
- [01] aws
while … receive-message … do … doneLoop until the DLQ returns no messages. Long-poll with 5s wait keeps SQS API calls cheap. - [02] jq
jq -c '.Messages[]?'Emit each message as a single-line JSON object — fed into the inner `while read` loop. - [03] aws
aws sqs send-message --queue-url "$SRC" --message-body "$BODY"Re-publish the original body to the source queue. Original message attributes are dropped — add `--message-attributes` from the message if your consumer needs them. - [04] aws
aws sqs delete-message --queue-url "$DLQ" --receipt-handle "$RH"Only delete from DLQ AFTER successful send (the `&&` enforces this). Loses zero messages even on partial failure.
Expected output (sample)
(silent — successful replays produce no stdout) Verify with: aws sqs get-queue-attributes --queue-url "$DLQ" --attribute-names ApproximateNumberOfMessages
Caveats & tips
- Test on a non-production DLQ first. Replay loops are easy to get wrong.
- If your DLQ has thousands of messages, run multiple workers in parallel — each receive-message only gets up to 10.
- Add `sleep 0.1` inside the inner loop if you hit SQS API throttling.