業界・業務から探す
導入目的・課題から探す
データ・AIについて学ぶ
News
Hakkyについて
ウェビナーコラム
◆トップ【データ基盤】
クラウドDWHを比較
Architecture
Redshift ServerlessRedshift
Amplify
データの保守運用
AI

執筆者:Handbook編集部

DLQにキューが入ったらSlackへアラートを送信する方法

概要

この記事では、SNS と SQS と Lambda を使用したメッセージ基盤の続きとして、DLQ にキューが入ったら Slack へアラートを送信する方法を紹介します。

下図の赤枠の箇所がこの記事で紹介する範囲となります。

赤枠の箇所の処理の流れとしては以下の通りです。

  1. DLQ にキューが入る
  2. CloudWatch が ① を検知
  3. SNS にアラーム
  4. Lambda で slack へメッセージ送信

Terraform

まずは環境を構築します。 SNS と SQS と Lambda を使用したメッセージ基盤で紹介した Terraform に以下を追加します。

resource "aws_cloudwatch_metric_alarm" "sqs_dlq_recieved_message" {
  for_each                  = var.api_handler
  alarm_name                = "${var.app_name}-${each.key}-sqs-dlq-recieved-message"
  comparison_operator       = "GreaterThanOrEqualToThreshold"
  evaluation_periods        = "1"
  metric_name               = "ApproximateNumberOfMessagesVisible"
  namespace                 = "AWS/SQS"
  period                    = "60"
  statistic                 = "Sum"
  threshold                 = "1"
  alarm_description         = "dead letter queue received message"
  alarm_actions             = [aws_sns_topic.alert.arn]
  insufficient_data_actions = []
  dimensions = {
    QueueName = aws_sqs_queue.sqs_dlq[each.key].name
  }
}

resource "aws_cloudwatch_metric_alarm" "sns_dlq_recieved_message" {
  alarm_name                = "${var.app_name}-sns-dlq-recieved-message"
  comparison_operator       = "GreaterThanOrEqualToThreshold"
  evaluation_periods        = "1"
  metric_name               = "ApproximateNumberOfMessagesVisible"
  namespace                 = "AWS/SQS"
  period                    = "60"
  statistic                 = "Sum"
  threshold                 = "1"
  alarm_description         = "dead letter queue received message"
  alarm_actions             = [aws_sns_topic.alert.arn]
  insufficient_data_actions = []
  dimensions = {
    QueueName = aws_sqs_queue.sns_dlq.name
  }
}

resource "aws_sns_topic" "alert" {
  name                        = "${var.app_name}-sqs-dlq-notify"
  content_based_deduplication = false
  fifo_topic                  = false
  policy = jsonencode(
    {
      Id = "__default_policy_ID"
      Statement = [
        {
          Sid    = "__default_statement_ID"
          Effect = "Allow"
          Principal = {
            AWS = "*"
          }
          Action = [
            "SNS:GetTopicAttributes",
            "SNS:SetTopicAttributes",
            "SNS:AddPermission",
            "SNS:RemovePermission",
            "SNS:DeleteTopic",
            "SNS:Subscribe",
            "SNS:ListSubscriptionsByTopic",
            "SNS:Publish",
          ]
          Resource = "arn:aws:sns:ap-northeast-1:${var.aws_account_id}:${var.app_name}-sqs-dlq-notify"
        }
      ]
      Version = "2008-10-17"
    }
  )
}

resource "aws_sns_topic_subscription" "alert" {
  protocol             = "lambda"
  endpoint             = aws_lambda_function.alert.arn
  topic_arn            = aws_sns_topic.alert.arn
  raw_message_delivery = false
}

resource "aws_ecr_repository" "alert" {
  name = "${var.app_name}-dlq-alert"

  encryption_configuration {
    encryption_type = "AES256"
  }
  image_scanning_configuration {
    scan_on_push = "true"
  }
  image_tag_mutability = "IMMUTABLE"
}

resource "aws_ecr_lifecycle_policy" "alert" {
  repository = aws_ecr_repository.alert.name
  policy     = jsonencode(local.ecr-lifecycle-policy)
}

resource "aws_lambda_function" "alert" {
  function_name = "${var.app_name}-lambda-dlq-alert"
  role          = aws_iam_role.lambda.arn
  package_type  = "Image"
  image_uri     = "${aws_ecr_repository.alert.repository_url}:v1"
  timeout       = 60
  memory_size   = 128

  lifecycle {
    ignore_changes = [image_uri]
  }

  environment {
    variables = {
      SLACK_WEBHOOK_URL = var.slack_webhook_url
    }
  }
}

resource "aws_lambda_permission" "alert" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.alert.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.alert.arn
}

terraform apply します。

現時点ではまだ ECR にイメージが存在しないため、Lambda の作成はエラーとなります。そのため、ECR にイメージを push した後で再度 terraform apply する必要があります。

Lambda 用 Docker イメージ作成

次に Lambda 用 Docker イメージを ECR へ push します。

lambda.py

slack へ CloudWatch アラームを送信するための Lambda 関数です。

import json
import urllib.request
import os

def lambda_handler(event, context):
    slack_webhook_url = os.environ['SLACK_WEBHOOK_URL']

    msg = json.loads(event['Records'][0]['Sns']['Message'])

    alarm_name = msg['AlarmName']
    alarm_description = msg['AlarmDescription']
    new_state_reason = msg['NewStateReason']
    region = msg['Region']
    account_id = msg['AWSAccountId']
    timestamp = msg['StateChangeTime']

    slack_message = {
        'attachments': [
            {
                'fallback': f'CloudWatch alarm {alarm_name} triggered.',
                'color': 'danger',
                'title': f'CloudWatch alarm {alarm_name} triggered.',
                'fields': [
                    {
                        'title': 'Description',
                        'value': alarm_description
                    },
                    {
                        'title': 'New state reason',
                        'value': new_state_reason
                    },
                    {
                        'title': 'Region',
                        'value': region
                    },
                    {
                        'title': 'Account ID',
                        'value': account_id
                    },
                    {
                        'title': 'Timestamp',
                        'value': timestamp
                    }
                ],
                'footer': 'AWS CloudWatch Alarm',
                'footer_icon': 'https://cloudonaut.io/cloudonaut_64.jpg'
            }
        ]
    }

    req = urllib.request.Request(slack_webhook_url, data=json.dumps(slack_message).encode('utf-8'), headers={'Content-Type': 'application/json'})
    response = urllib.request.urlopen(req)
    return response.read()

requirements.txt

urllib3==1.26.12

Dockerfile

Dockerfile は下記です。Docker イメージを作成して ECR へ push します。

FROM public.ecr.aws/lambda/python:3.8

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["lambda.lambda_handler"]
info
備考

ECR へイメージを push したら、再度 terraform apply を実施して Lambda を作成します。

DLQ アラート発行

環境が整ったので、DLQ アラートが slack へ送信されるか試してみます。

SNS と SQS と Lambda を使用したメッセージ基盤#メッセージ発行を再度実行します。

DLQ にキューが入ると CloudWatch アラームがアラーム状態に変化し、Slack へアラームの内容が送信されました。

まとめ

この記事では、SNS と SQS と Lambda を使用したメッセージ基盤の続きとして、DLQ にキューが入ったら Slack へアラートを送信する方法を紹介しました。DLQ にキューが入った際にアラートすることで、処理の失敗をリアルタイムで把握することが可能です。

参考

info
備考

Hakky ではエンジニアを募集中です!まずは話してみたいなどでも構いませんので、ぜひお気軽に採用ページからお問い合わせくださいませ。

2025年07月03日に最終更新
読み込み中...