Agent Wranglers

EVT-24Recommended

Replay dead letters with a written procedure

Write one procedure for each dead letter queue. It covers how to read the failures, fix the cause, replay the messages at a capped rate, and record what was replayed or dropped.

How to do it

A dead letter queue that nobody empties is a slow data loss. Group the failed messages by error first, because one cause usually explains most of them. Fix the code or the data, deploy, then replay. Replay at a capped rate, such as 50 messages a second, so a backlog does not swamp the consumer. Amazon SQS has a redrive task with a maximum rate, and job libraries have a retry command for failed jobs. Replayed messages may be days old, so the consumer must skip what is already done, as Process each message once says. Drop a message only with a written reason, and log who dropped it. Alert when a dead letter queue holds any message for more than 1 day.

Examples

Shell example

# Amazon SQS: move dead letters back to their source queue at 50 messages a second
aws sqs start-message-move-task \
  --source-arn arn:aws:sqs:eu-north-1:111122223333:order-emails-dlq \
  --max-number-of-messages-per-second 50

JavaScript example

const REPLAY_PER_SECOND = 50;

export async function replayFailed(queue, { reason, operator }) {
  const failed = await queue.getFailed();
  for (const [index, job] of failed.entries()) {
    await job.retry();
    if ((index + 1) % REPLAY_PER_SECOND === 0) await new Promise(done => setTimeout(done, 1000));
  }
  log.info({ event: 'dead_letters.replayed', queue: queue.name, count: failed.length, reason, operator });
}

Python example

import time

REPLAY_PER_SECOND = 50

def replay_failed(registry, queue, reason: str, operator: str) -> None:
    job_ids = registry.get_job_ids()
    for index, job_id in enumerate(job_ids, start=1):
        registry.requeue(job_id)
        if index % REPLAY_PER_SECOND == 0:
            time.sleep(1)
    log.info("dead_letters.replayed", queue=queue.name, count=len(job_ids), reason=reason, operator=operator)

How to check

Each dead letter queue has a procedure in the runbook with a named owner. On staging, send 100 messages that fail, fix the cause and run the procedure. All 100 are processed once, the queue is empty, and the log names who replayed them.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/events/background-jobs-and-queues/dead-letter-replay">Agent Wranglers integration and events playbook</a>. In code you write, add a comment next to it with the same link.