🗃️
AWS Lambda で S3 にアップロードされたファイルを Discord に通知する
AWS のお勉強がてらに書いておく。
やりたいこと
はじめに以下の背景がある。
- AWS Lambda で遊んでみたい
- Lambda 単体だけではなく、他の AWS サービスも絡む形でシステムを構成したい
実際ネタは何でも良いのだが、手軽かつ実用的な実装を考えたときに「AWS Lambda で S3 にアップロードされたファイルを Discord に通知する」というのを思いついたのでこれを実装する。
前提
以下すべてが済んでいれば、Python で型ヒントを用いつつコーディングができるようになる。逆に以下の前提がない場合、よくわからないデータを四苦八苦しながら解読することになりうる。
- Python 3.12.2 で実装する。
- 以下のパッケージが Lambda Layers で導入されていること
-
keithrozario/Klayers の
requests
ARN:arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-p312-requests:2
-
aws-powertools/powertools-lambda-python
ARN:arn:aws:lambda:ap-northeast-1:017000801446:layer:AWSLambdaPowertoolsPythonV2:64
-
keithrozario/Klayers の
レイヤーの導入について多くは書かないが、追加するボタンは AWS Lambda 関数のページ最下部にある。分かりづらい場所にあるので念のため付記しておく。
実装方針
- Discord の適当なチャンネルの Webhook を作成する
- S3 バケットをなんでもいいので作成する。
- Lambda 関数を作成する。
- 関数名はなんでもよい。
- Lambda Layers にライブラリを足しておくのを忘れないようにする。
- 環境変数に (1) で控えた Webhook を書き込む。今回は
DISCORD_WEBHOOK
とした。
- Lambda のトリガーに S3 を追加する。バケット名とトリガーとなるイベントの指定が必要であるので、以下の画像の要領で設定する。
- Python でロジック本体を書く。
Python による実装
ポイントは以下の通り。
- Powertools for AWS Lambda のお陰で型ヒントを使えるようになる。ただ
S3Event
なんかはデータ構造の定義というよりラッパークラスなのでちょっと扱いに癖がある。 - Discord の Webhook は AWS Lambda の環境変数から取ってくるようにする。これによりコード本体に事実上のシークレットである Webhook URI を書かずに済むのでより安全かつ可搬なコードになる。
import os
from aws_lambda_powertools.utilities.typing import LambdaContext
from aws_lambda_powertools.utilities.data_classes import S3Event
import requests
HEADER = {"Content-Type": "application/json"}
def lambda_handler(event, context: LambdaContext):
if (webhook := os.environ.get("DISCORD_WEBHOOK")) is None:
return {"statusCode": 500}
event = S3Event(event)
message = f"New Item: s3://{event.bucket_name}/{event.object_key}"
body = {"content": message}
response = requests.post(webhook, json=body, headers=HEADER)
try:
response.raise_for_status()
return {"statusCode": 200}
except requests.HTTPError:
return {"statusCore": 500}
これで S3 にファイルをアップロードすると Discord のチャンネルに通知が飛ぶようにできる。
メモ
- Lambda 関数を作るときに関数専属(?)の CloudWatch ロググループが追加される。
print()
なんかで出力したログは CloudWatch で見られる。
Discussion