
- 1. はじめに(目的・背景)
- 2. そもそも Lambda の DLQ とは?
- 3. Lambda の呼び出しモードによる DLQ 挙動の違い
- 4. Lambda の非同期呼び出しで通知を送る
- 5. Lambda の同期呼び出しで通知を送る
- 6. まとめ
1. はじめに(目的・背景)
「Lambda に デッドレターキュー(以下、DLQ)を設定したのに、なぜか通知が飛ばない…?」という罠にハマったことはありませんか?
実は、Lambda の DLQ は非同期呼び出し時にのみ動作し、同期呼び出し時には一切動作しません。 たとえば、API Gateway から同期で Lambda を呼び出しているケースでは、例外レスポンスはそのままクライアントに返されるだけで、DLQ で指定した宛先には通知は行きません。
本記事では、以下のような疑問に答えながら、実務での Lambda 利用において、通知の取りこぼしを防ぐ設計を解説します。
「同期/非同期で DLQ の挙動ってどう違うの?」
「非同期 Lambda の失敗を確実に通知したい」
「DLQ に入ったイベントを メールで通知したい」
2. そもそも Lambda の DLQ とは?
Lambda の Dead Letter Queue(DLQ)とは、処理が失敗したイベントを後続処理のために保存しておく仕組みです。これにより、失敗したイベントを再実行したり、トラブルシューティングの材料として活用したりできます。
| 項目 | 内容 |
|---|---|
| 対象 | 非同期呼び出し時の失敗イベント |
| リトライ回数 | 最大 2 回(変更可能) |
| 転送先 | SQS または SNS トピック(いずれか1つ) |
| 用途 | 失敗イベントの保全/再実行/通知連携 |
DLQ の活用によって、Lambda 単体では拾いきれない失敗イベントを検知・蓄積し、後続の通知や自動対応へ繋げることが可能になります。
障害調査や再処理フローの設計にも大きく貢献するため、非同期処理を扱う際は忘れずに設定しておきましょう。
3. Lambda の呼び出しモードによる DLQ 挙動の違い
Lambda 関数は呼び出し方法によって挙動が異なり、大きく「非同期呼び出し」と「同期呼び出し」に分類されます。
非同期呼び出し:呼び出し元がレスポンスを待たずに処理を委譲する呼び出し方法です。SNS トピック や EventBridge などのイベントソースによる起動が代表的です。
同期呼び出し:呼び出し元がレスポンスを待ち、結果を即時受け取る呼び出し方法です。たとえば API Gateway や SDK から直接 Invoke するケースが該当します。
これらの違いにより、DLQ の動作可否にも明確な違いが生まれます。
3-1. 非同期呼び出し(Event / InvokeAsync)の挙動
たとえば EventBridge → Lambda や SNS トピック → Lambda など、非同期イベントでトリガーされる場合です。
Lambda は非同期に呼び出され、最大 2 回まで自動リトライされます(※再試行回数は設定可能)。
すべてのリトライに失敗すると、DLQ( SQS または SNS )へ転送されます。
Lambda Destinations を使って成功/失敗の通知先を個別に指定することも可能です。
3-2. 同期呼び出し(RequestResponse / Invoke)の挙動
処理中にエラーが発生した場合は、即時に呼び出し元へ例外レスポンスが返却されます。
DLQ は機能しません(=DLQ にはイベントは送信されません)。
4. Lambda の非同期呼び出しで通知を送る
Lambda を非同期で呼び出した際の失敗を通知する代表的な2つの方法をご紹介します。
4-1. パターン①:非同期呼び出しの DLQ 設定( SNS または SQS )
Lambda の「非同期呼び出し設定」画面から、DLQ の送信先を SNS トピック または SQS キュー に指定する方法です。
設定
ここでは通知先として SNS トピックを例に紹介します。

DLQ の通知先として SNS トピックを指定する場合、Lambda の実行ロールに sns:Publish 権限が必要です。権限が不足していると、以下のようなエラーで保存に失敗します。
The provided execution role does not have permissions to call Publish on SNS

下記のように、宛先の SNS トピックに対する sns:Publish 権限を付与した IAM ポリシーを、Lambda の実行ロールに追加してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"sns:Publish"
],
"Resource": [
"< SNS トピックの ARN >"
]
}
]
}
上記の IAM 権限を付与することで、設定を正常に保存できるようになります。

通知動作の確認
非同期で Lambda を呼び出し、あえて実行エラーを発生させることで DLQ 通知の動作を確認できます。 今回は、上記のキャプチャの通り、再試行回数を 2 に設定して動作確認を行いました。
以下のコードで、存在しない関数 hello_world_test() を呼び出してエラーを発生させます。
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def hello_world():
return "Hello World!"
def lambda_handler(event, context):
try:
# 実処理
result = hello_world_test()
return {
'statusCode': 200,
'body': json.dumps({'message': 'Success', 'data': result})
}
except Exception as e:
logger.error("エラーが発生しました: %s", str(e), exc_info=True)
raise
EventBridge Scheduler から 上記の Lambda を非同期で呼び出した結果、SNS トピック経由でメール通知が送信されました。

以下は Lambda の実行ログです。 Lambda が1回実行後、2回再試行されたことがわかります。

4-2. パターン②:Lambda Destinations + EventBridge
Lambda 関数の「送信先を追加」画面から、送信先タイプを選択して設定する方法です。
設定
ここでも通知先として SNS トピックを例に紹介します。

この方法には以下のような特徴があります。
成功・失敗それぞれに別の送信先を設定可能
成功時・失敗時の両方に通知先を指定できるため、ユースケースに応じた柔軟な通知ルールを構成できます。選択できる送信先のサービスが豊富
パターン①と比べて、より多くの AWS サービス( SNS、SQS、Lambda、EventBridge、S3 など)を通知先として選択できます。
2025年10月時点で、非同期呼び出しの失敗時に設定できる送信先としては以下の通りです。

正常時の送信先タイプとしては、以下のAWSサービスが選択できます。
なお、S3 バケットは「失敗時のみ」選択できる宛先のため、正常時にはプルダウンの候補に表示されず、選択できなくなっています。
正常時は SNS トピック / SQS キュー / Lambda 関数 / EventBridge イベントバス のみ選択可能です。

以下の通り、失敗時と正常時の両方で送信先を設定することも可能です。

パターン①では、SNS トピックに通知するために sns:Publish 権限を手動で Lambda 実行ロールに追加する必要がありました。
一方、「送信先を追加」の設定画面から SNS トピックを設定した場合は、AWS 側が自動的に必要な権限(sns:Publish)を付与してくれます。

なお、設定を3回繰り返すと、すでに権限が付与されているかどうかに関わらず、同一内容のポリシーが3つ自動生成されていました。
そのため、「送信先を追加」で何度も設定・解除・再設定を行った場合、重複した IAM ポリシーが複数作成される可能性があるため注意が必要です。

通知動作の確認
パターン①の DLQ 通知設定を無効化し、Lambda Destinations 経由で失敗時に SNS 通知されるか検証してみます。

EventBridge Scheduler → Lambda の構成で、Lambda 関数内に意図的なエラーを発生させた結果、SNS 経由でメール通知が送信されました。
このイベントには、リクエスト/レスポンスの詳細情報が含まれており、パターン①の通知よりもやや詳細な形式で通知されます。

以下は Lambda の実行ログです。 Lambda が 1 回実行された後、2 回再試行されたことが確認できます。

Lambda は非同期呼び出し時に 最大 2 回まで再試行されますが、この回数はパターン①と同様に「非同期呼び出し」設定で変更可能です。
たとえば、再試行回数を「1」に設定した場合の挙動は以下の通りです。
再試行回数を「1」に設定すると、

以下の通り、1 回のみ再試行されたことが確認できます。

5. Lambda の同期呼び出しで通知を送る
Lambda の同期呼び出しの処理で通知を送る方法としては、いくつかありますが、たとえば以下があります。
5-1. パターン①:Lambda 内で明示的に SNS 通知
DLQでは通知できないため、Lambda 関数内でエラー時に明示的に SNS 通知を行う方法です。
設定
たとえば、以下のように Lambda のコードのエラー処理の中で宛先に SNS などを指定する方法です。
import boto3
import json
import logging
import os
sns = boto3.client('sns')
SNS_TOPIC_ARN = os.environ.get('SNS_TOPIC_ARN')
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def hello_world():
return "Hello World!"
def notify_error(message: str, subject: str = 'Lambda Error Notification'):
# SNS へエラー通知を送信
try:
sns.publish(
TopicArn=SNS_TOPIC_ARN,
Message=json.dumps({'error': message}),
Subject=subject
)
except Exception as pub_err:
# SNS 通知自体が失敗したらログに残す
logger.exception(f'Failed to publish to SNS: {pub_err}')
def lambda_handler(event, context):
try:
# 実処理
result = hello_world()
return {
'statusCode': 200,
'body': json.dumps({'message': 'Success', 'data': result})
}
except Exception as e:
# SNS 通知
notify_error(str(e))
raise
通知動作の確認
上記のコードで Lambda のエラーが発生すると、以下のような通知メールが SNS トピック経由で届きます。

5-2. パターン②:CloudWatch Alarm で Lambda のエラーを検知する方法
この方法では、Lambda 関数が同期呼び出しか非同期呼び出しかを問わず、CloudWatch メトリクスを用いて実行エラーを検知・通知できます。
設定
CloudWatch メトリクスの名前空間「AWS/Lambda」内にある Errors メトリクスを選択し、アラームを作成します。

CloudWatch Alarm の評価期間(上記のキャプチャでは 5 分)は、Lambda 関数の実行時間よりも十分に長く設定する必要があります。
なぜなら、CloudWatch メトリクスのタイムスタンプは 「関数の開始時刻」 に記録されるため、長時間実行される関数では評価対象から漏れてしまう可能性があるためです。
たとえば、評価期間が 5 分で Lambda が 10 分後に失敗した場合、その失敗は評価期間外とみなされ、アラームが発報されない可能性があります。
実際、公式ドキュメントにも以下の通り明記されています。
メトリクスのタイムスタンプには、関数が呼び出された時間が反映されます。呼び出し時間によっては、数分後にメトリクスが生成される場合があります。たとえば、関数のタイムアウトが 10 分の場合は、正確なメトリクスを得るために過去 10 分以上を確認します。
※引用:AWS公式ドキュメント「Lambda 関数のメトリクスの表示」(2025年10月20日アクセス)URL:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/monitoring-metrics-view.html
統計は「合計(Sum)」を指定します。
これは、以下のメトリクス選択画面で表示される「意味のある統計:合計」に基づいています。

今回は「1 回以上のエラーでアラームを発報」とする設定にしています。

アラームが発報された際に通知を受け取るために、SNS トピックを指定します。

アラーム名は任意で設定し、必要に応じてアラームの説明を入力した上でアラームを作成します。

今回は検証のため、Lambda 関数内で存在しない関数 hello_world_test() を呼び出してエラーを発生させます。
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def hello_world():
return "Hello World!"
def lambda_handler(event, context):
try:
# 実処理
result = hello_world_test()
return {
'statusCode': 200,
'body': json.dumps({'message': 'Success', 'data': result})
}
except Exception as e:
logger.error("エラーが発生しました: %s", str(e), exc_info=True)
raise
通知動作の確認
Lambda 関数をテスト実行ボタンから実行し、エラー終了させます。

エラーが発生すると、CloudWatch Alarm が設定されたしきい値を検知し、SNS を通じてメール通知が送信されます。

この方法は、同期呼び出しでも非同期呼び出しでも有効であるため、同期呼び出しでのエラー検知にも有効です。
6. まとめ
本記事では、「Lambda に DLQ を設定しても通知が飛ばないのはなぜか?」という疑問に端を発し、Lambda の呼び出しモードごとの DLQ 挙動の違いと、通知の取りこぼしを防ぐための実践的な方法を紹介しました。
特に以下のようなポイントは、Lambda を用いた運用設計において重要な知識となります。
Lambda の DLQ は非同期呼び出し時にしか動作しない
同期呼び出しでは、DLQ にイベントが流れない非同期処理の通知手段として DLQ( SNS / SQS )や Lambda Destinations が有効
Lambda Destinations は成功・失敗時の宛先を柔軟に設定できる同期呼び出し時の通知には、Lambda 内での明示的な SNS 通知実装や CloudWatch Alarm の活用が有効
CloudWatch Alarm を使えば、呼び出しモードを問わずエラー通知が可能
一方で、実装時には以下のような注意点にも触れました。
Lambda Destinations の設定を繰り返すと、IAM ポリシーが重複生成される
CloudWatch Alarm の評価期間が Lambda の実行時間より短いと、アラートが正しく発報されない
これらの特性や注意点を理解し、呼び出しモードに応じて適切な通知手段を設計することで、実運用における障害検知の確実性が大きく向上します。
本記事が、Lambda を活用する皆さまの運用設計やトラブルシューティングの一助となれば幸いです。