Files
ewoooc/n8n-workflows/22-alert-deduplication.json
OoO d6d8777e41
All checks were successful
CD Pipeline / deploy (push) Successful in 1m12s
V10.601 收斂 Gemini 與密鑰治理
2026-06-06 14:52:46 +08:00

122 lines
5.0 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"name": "告警去重與抑制機制",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "alert-receiver",
"options": {}
},
"id": "webhook",
"name": "告警接收器",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [240, 300]
},
{
"parameters": {
"jsCode": "const alert = $input.first().json;\nconst now = Date.now();\nconst alertKey = `${alert.environment}_${alert.alertType}_${alert.service}`;\n\n// 從 static data 讀取告警歷史\nconst alertHistory = $getWorkflowStaticData('global');\nif (!alertHistory.alerts) {\n alertHistory.alerts = {};\n}\n\nconst lastAlert = alertHistory.alerts[alertKey];\nconst cooldownMinutes = {\n 'critical': 5, // 嚴重告警5 分鐘內不重複\n 'warning': 15, // 警告15 分鐘內不重複\n 'info': 60 // 資訊1 小時內不重複\n};\n\nconst cooldown = (cooldownMinutes[alert.severity] || 15) * 60 * 1000;\nconst shouldSend = !lastAlert || (now - lastAlert.timestamp > cooldown);\n\nif (shouldSend) {\n alertHistory.alerts[alertKey] = {\n timestamp: now,\n count: (lastAlert?.count || 0) + 1\n };\n}\n\n// 清理超過 24 小時的歷史\nObject.keys(alertHistory.alerts).forEach(key => {\n if (now - alertHistory.alerts[key].timestamp > 24 * 60 * 60 * 1000) {\n delete alertHistory.alerts[key];\n }\n});\n\nreturn [{\n json: {\n ...alert,\n shouldSend,\n suppressReason: shouldSend ? null : `冷卻中 (${cooldownMinutes[alert.severity]}分鐘)`,\n repeatCount: alertHistory.alerts[alertKey]?.count || 1\n }\n}];"
},
"id": "dedup",
"name": "告警去重邏輯",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [460, 300]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "should-send",
"leftValue": "={{ $json.shouldSend }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-send",
"name": "是否發送?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [680, 300]
},
{
"parameters": {
"jsCode": "const alert = $input.first().json;\nconst now = new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' });\n\nconst severityEmoji = {\n 'critical': '🔴',\n 'warning': '🟠',\n 'info': '🔵'\n};\n\nconst envEmoji = {\n 'UAT': '🟦',\n 'GCP': '🟥'\n};\n\nlet message = `${severityEmoji[alert.severity] || '⚪'} <b>${envEmoji[alert.environment] || ''} ${alert.title}</b>\\n\\n`;\nmessage += `📍 環境: ${alert.environment}\\n`;\nmessage += `🔧 服務: ${alert.service}\\n`;\nmessage += `📝 詳情: ${alert.description}\\n`;\n\nif (alert.repeatCount > 1) {\n message += `🔄 重複次數: ${alert.repeatCount}\\n`;\n}\n\nmessage += `⏰ 時間: ${now}`;\n\nreturn [{ json: { message } }];"
},
"id": "format",
"name": "格式化訊息",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [900, 200]
},
{
"parameters": {
"url": "https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/sendMessage",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"chat_id\": \"5619078117\",\n \"parse_mode\": \"HTML\",\n \"text\": \"{{ $json.message }}\"\n}",
"options": {}
},
"id": "telegram",
"name": "發送 Telegram",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1120, 200]
},
{
"parameters": {
"jsCode": "// 記錄被抑制的告警(供分析用)\nconst alert = $input.first().json;\nconsole.log(`告警被抑制: ${alert.alertType} - ${alert.suppressReason}`);\nreturn [{ json: { suppressed: true, reason: alert.suppressReason } }];"
},
"id": "log-suppressed",
"name": "記錄抑制",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [900, 400]
}
],
"connections": {
"告警接收器": {
"main": [
[{ "node": "告警去重邏輯", "type": "main", "index": 0 }]
]
},
"告警去重邏輯": {
"main": [
[{ "node": "是否發送?", "type": "main", "index": 0 }]
]
},
"是否發送?": {
"main": [
[{ "node": "格式化訊息", "type": "main", "index": 0 }],
[{ "node": "記錄抑制", "type": "main", "index": 0 }]
]
},
"格式化訊息": {
"main": [
[{ "node": "發送 Telegram", "type": "main", "index": 0 }]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [],
"triggerCount": 0,
"updatedAt": "2026-02-07T17:00:00.000Z",
"versionId": "1"
}