1. 結論(この記事で得られること)
Lambda から Slack への通知実装、シンプルに見えて意外と奥が深いです。私も新人の頃、「とりあえず動けばいいや」で作って、本番で文字化けやリトライ地獄に遭遇しました。
この記事では以下が手に入ります:
- 3つの実装パターン(Incoming Webhook / Slack App / EventBridge 経由)の使い分け基準
- 本番で安全に運用できるコード(エラーハンドリング・リトライ・テスト込み)
- AI(Claude/GPT)を使った最速デバッグ術(ログから原因特定まで5分)
- 失敗パターン集(私が実際に踏んだ地雷を共有します)
「明日からプロジェクトで使える」レベルまで落とし込みます。
2. 前提(環境・読者層)
想定読者
-
Lambda で何らかの処理を実装した経験がある
-
Slack の Webhook URL は取得できる
-
Python or Node.js のどちらかが読める
-
Lambda: Python 3.11 / Node.js 18.x(どちらでも OK)
-
Slack: Incoming Webhook または Slack App
-
IaC: Terraform / CloudFormation(参考として提示)
3. Before:よくあるつまずきポイント
3-1. 「とりあえず動いた」で終わる危険性
初学者が書きがちなコード:
import json
import urllib.request
def lambda_handler(event, context):
url = "https://hooks.slack.com/services/XXX/YYY/ZZZ"
message = {"text": "処理完了"}
req = urllib.request.Request(url, json.dumps(message).encode())
urllib.request.urlopen(req)
return {"statusCode": 200}
何が問題か?
① エラーハンドリングが皆無 → Slack 側エラーで Lambda が異常終了
② タイムアウト考慮なし → 30秒待ち続けて Lambda コストが膨らむ
③ リトライ制御なし → 一時的なネットワーク障害で通知が消失
④ テストが困難 → URL がハードコード、モックできない
私も昔、これで本番障害を起こしました。Slack の API が瞬間的に落ちたとき、Lambda が全部エラーになって DLQ が溢れた経験があります。
3-2. よくある質問と誤解
Webhook で十分では?
現実: エラー時に再送制御が難しい。SQS 経由がベター
同期的に送って良い?
現実: Lambda の実行時間が伸びる。非同期化推奨
Secrets Manager は必須?
現実: 環境変数でも可。ただし暗号化は必須
4. After:基本的な解決パターン
4-1. パターン選定フローチャート
通知の重要度は高い?
├─ Yes → パターン3(EventBridge + SQS + Lambda)
└─ No →
├─ リッチなフォーマットが必要?
│ ├─ Yes → パターン2(Slack App + Block Kit)
│ └─ No → パターン1(Incoming Webhook)
4-2. パターン1:Incoming Webhook(基本形)
使いどころ:シンプルな通知、開発環境、PoC
import json
import urllib.request
import urllib.error
import os
from typing import Dict, Any
SLACK_WEBHOOK_URL = os.environ["SLACK_WEBHOOK_URL"]
TIMEOUT_SECONDS = 10
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
try:
send_slack_notification(event.get("message", "No message"))
return {"statusCode": 200, "body": "Notification sent"}
except Exception as e:
print(f"Error sending notification: {e}")
# ここで失敗しても Lambda 自体は成功させる(通知失敗で本処理を止めない)
return {"statusCode": 200, "body": "Notification failed but ignored"}
def send_slack_notification(message: str) -> None:
payload = {
"text": message,
"username": "Lambda Bot",
"icon_emoji": ":robot_face:"
}
req = urllib.request.Request(
SLACK_WEBHOOK_URL,
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST"
)
try:
with urllib.request.urlopen(req, timeout=TIMEOUT_SECONDS) as response:
if response.status != 200:
raise Exception(f"Slack API returned {response.status}")
except urllib.error.URLError as e:
raise Exception(f"Network error: {e}")
ポイント:
- タイムアウトを明示(デフォルトは無制限で危険)
- 通知失敗でも Lambda は成功扱い(本処理と通知を分離)
- 環境変数から URL 取得(ハードコード厳禁)
4-3. パターン2:requests ライブラリ使用(Node.js)
Python の 「urllib」 は正直使いづらいので、実務では 「requests」 を使います。ただし Lambda Layer が必要。
Node.js なら標準で楽:
const https = require('https');
exports.handler = async (event) => {
const webhookUrl = process.env.SLACK_WEBHOOK_URL;
const message = event.message || 'No message';
const payload = JSON.stringify({
text: message,
username: 'Lambda Bot',
icon_emoji: ':robot_face:'
});
const url = new URL(webhookUrl);
const options = {
hostname: url.hostname,
path: url.pathname + url.search,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(payload)
},
timeout: 10000
};
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
if (res.statusCode === 200) {
resolve({ statusCode: 200, body: 'OK' });
} else {
console.error(`Slack API error: ${res.statusCode} ${data}`);
resolve({ statusCode: 200, body: 'Notification failed but ignored' });
}
});
});
req.on('error', (e) => {
console.error(`Request error: ${e.message}`);
resolve({ statusCode: 200, body: 'Notification failed but ignored' });
});
req.on('timeout', () => {
req.destroy();
console.error('Request timeout');
resolve({ statusCode: 200, body: 'Notification failed but ignored' });
});
req.write(payload);
req.end();
});
};
Node.js を選ぶ理由:
- 標準ライブラリで完結(Layer 不要)
- 非同期処理が自然に書ける
- コールドスタートが Python より若干速い