1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS Lambda+SNSのメール配信におけるエラーハンドリングを実装する

Last updated at Posted at 2024-10-31

はじめに

本記事ではAWSのLambdaとSNSを使用したメール送信において、エラーハンドリングを実装していきます。

ゴール

下記の2点を確認することをゴールとします。

  1. Lambda→SNS段階のエラーを検知し、エラーメールを送信できてる事
  2. SNS→メール配信段階のエラー検知し、エラーメールを送信できてる事

処理フロー

【正常系】
Lambda → SNS → メール配信

【エラー系1: Lambda→SNS段階】
Lambda → エラー発生 → エラーメール送信

【エラー系2: SNS→メール配信段階】
SNS → エラー発生 → CloudWatchメトリクスで検知 → アラーム状態 → エラーメール送信

作るもの

  • AWS Lambda:1つ
  • Amazon SNS:1つ
  • Amazon CloudWatch:1つ

1. SNSトピックの作成

トピック・サブスクリプションの作成

トピックとサブスクリプションの作成手順については、次の記事に記載されてる方法を参照ください。

2. Lambda関数の作成

LambdaからSNSを利用したメール通知に関しても、次の記事に記載されてるソースを参考に実装しています。

lambda_function.py
import json
from notifier import send_notification, send_error_notification

def lambda_handler(event, context):
    TOPIC_ARN = 'SNSトピックのARN'

    subject = "Lambda からの通知"
    message = "テスト通知メッセージ"
    
    try:
        response = send_notification(TOPIC_ARN, message, subject)
        
        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': '通知が送信されました',
                'messageId': response['MessageId']
            })
        }
        
    except Exception as e:
        error_message = str(e)
        
        send_error_notification(
            TOPIC_ARN,
            error_message,
            "Lambda-SNS通信エラー"
        )
        
        return {
            'statusCode': 500,
            'body': json.dumps({
                'error': 'メール送信に失敗しました',
                'details': error_message
            })
        }
notifier.py
notifier.py
import json
import boto3
from datetime import datetime

sns = boto3.client('sns')

def send_notification(topic_arn, message, subject):
    response = sns.publish(
        TopicArn=topic_arn,
        Message=message,
        Subject=subject
    )
    return response


def send_error_notification(topic_arn, error_message, error_type):
    error_subject = f"【エラー通知】{error_type}"
    error_body = f"""
エラーが発生しました。
発生時刻: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
エラー種別: {error_type}
エラー詳細: {error_message}
    """
    
    try:
        sns.publish(
            TopicArn=topic_arn,
            Message=error_body,
            Subject=error_subject
        )
    except Exception:
        pass

Lambdaを動かす際にはIAMのポリシーからSNSの権限付与を行っていてください。

3. CloudWatchアラームの作成

  • 「アラーム」→「すべてのアラーム」を選択し、「アラームの作成」をクリック
  • メトリクスの選択:
    • メトリクス名: NumberOfNotificationsFailed
    • トピック名: 監視対象のSNSトピック名を選択

image.png

  • メトリクスオプションの設定:
    • 統計: Sum
    • 期間: 5分

image.png

  • 条件の設定
    • しきい値の種類: 静的
    • アラーム条件: 以上
    • しきい値: 1

image.png

  • アラームアクションの設定
    • アラーム状態トリガー:アラーム状態
    • SNSトピックを選択
    • 通知の送信先:エラー通知用のSNSトピック

image.png

動作の確認

正常系の確認

Lambdaをテスト実行し、正常にメールが通知されることを確認できました。

image.png

内容
件名:Lambda からの通知
本文:これはテスト通知メッセージです。

エラー系1: Lambda→SNS通信エラーの確認

意図的にLambdaのソースを誤ったものにし、Lambdaを実行してみます。

誤った例
response = sns.publish(
        TopicArn=topic_arnあああ,
        Message=message,
        Subject=subject
    )

Lambda実行後、Lambda側で定義した内容のエラーメールが送信されることを確認できました。

image.png

エラーメール
件名:【エラー通知】Lambda-SNS通信エラー
本文:
エラーが発生しました。
発生時刻: 2024-10-31 15:48:41
エラー種別: Lambda-SNS通信エラー
エラー詳細: name 'topic_arnあああ' is not defined

エラー系2:SNS配信エラーの確認

AWS CLIを使用してメトリクスをアラーム状態にし、配信エラーを擬似的に再現します。

# アラーム状態に設定
aws cloudwatch set-alarm-state \
  --alarm-name アラーム名 \
  --state-value ALARM \
  --state-reason "Testing alarm notification"

次のコマンドではアラームをOK状態に戻すことができます。

# OK状態に設定
aws cloudwatch set-alarm-state \
  --alarm-name アラーム名 \
  --state-value OK \
  --state-reason "Test completed"

コマンド実行後、CloudWatchアラームによるエラーメールが送信されることを確認できました。

image.png

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?