136 lines
7.1 KiB
JSON
136 lines
7.1 KiB
JSON
{
|
||
"name": "容量規劃與趨勢分析",
|
||
"nodes": [
|
||
{
|
||
"parameters": {
|
||
"rule": {
|
||
"interval": [
|
||
{
|
||
"field": "cronExpression",
|
||
"expression": "0 8 1 * *"
|
||
}
|
||
]
|
||
}
|
||
},
|
||
"id": "schedule",
|
||
"name": "每月 1 日 08:00",
|
||
"type": "n8n-nodes-base.scheduleTrigger",
|
||
"typeVersion": 1.2,
|
||
"position": [240, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"url": "https://mo.wooo.work/api/system/db/stats",
|
||
"options": { "timeout": 30000 }
|
||
},
|
||
"id": "uat-db-stats",
|
||
"name": "UAT DB 統計",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.2,
|
||
"position": [460, 200],
|
||
"continueOnFail": true
|
||
},
|
||
{
|
||
"parameters": {
|
||
"url": "https://momo.wooo.work/api/system/db/stats",
|
||
"options": { "timeout": 30000 }
|
||
},
|
||
"id": "gcp-db-stats",
|
||
"name": "GCP DB 統計",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.2,
|
||
"position": [460, 400],
|
||
"continueOnFail": true
|
||
},
|
||
{
|
||
"parameters": {
|
||
"mode": "combine",
|
||
"combineBy": "combineAll",
|
||
"options": {}
|
||
},
|
||
"id": "merge",
|
||
"name": "合併結果",
|
||
"type": "n8n-nodes-base.merge",
|
||
"typeVersion": 3,
|
||
"position": [680, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const results = $input.all();\nconst now = new Date();\nconst monthKey = now.toISOString().slice(0, 7);\n\n// 從 static data 讀取歷史數據\nconst history = $getWorkflowStaticData('global');\nif (!history.monthly) {\n history.monthly = [];\n}\n\nconst uatStats = results[0]?.json || {};\nconst gcpStats = results[1]?.json || {};\n\n// 記錄本月數據\nhistory.monthly.push({\n month: monthKey,\n uat: {\n dbSize: uatStats.database_size_mb || 0,\n connections: uatStats.connection_count || 0,\n tableCount: uatStats.table_count || 0\n },\n gcp: {\n dbSize: gcpStats.database_size_mb || 0,\n connections: gcpStats.connection_count || 0,\n tableCount: gcpStats.table_count || 0\n }\n});\n\n// 保留最近 12 個月\nif (history.monthly.length > 12) {\n history.monthly.shift();\n}\n\n// 計算成長趨勢\nconst monthsData = history.monthly;\nlet uatGrowthRate = 0;\nlet gcpGrowthRate = 0;\nlet uatPrediction = 0;\nlet gcpPrediction = 0;\n\nif (monthsData.length >= 2) {\n const lastMonth = monthsData[monthsData.length - 2];\n const thisMonth = monthsData[monthsData.length - 1];\n \n if (lastMonth.uat.dbSize > 0) {\n uatGrowthRate = ((thisMonth.uat.dbSize - lastMonth.uat.dbSize) / lastMonth.uat.dbSize * 100).toFixed(1);\n // 預測 6 個月後的大小\n uatPrediction = (thisMonth.uat.dbSize * Math.pow(1 + parseFloat(uatGrowthRate) / 100, 6)).toFixed(0);\n }\n \n if (lastMonth.gcp.dbSize > 0) {\n gcpGrowthRate = ((thisMonth.gcp.dbSize - lastMonth.gcp.dbSize) / lastMonth.gcp.dbSize * 100).toFixed(1);\n gcpPrediction = (thisMonth.gcp.dbSize * Math.pow(1 + parseFloat(gcpGrowthRate) / 100, 6)).toFixed(0);\n }\n}\n\n// 容量警告閾值\nconst DB_SIZE_WARNING = 8000; // 8GB\nconst DB_SIZE_CRITICAL = 9000; // 9GB\n\nconst uatWarning = (uatStats.database_size_mb || 0) > DB_SIZE_WARNING;\nconst gcpWarning = (gcpStats.database_size_mb || 0) > DB_SIZE_WARNING;\nconst uatPredictionWarning = parseFloat(uatPrediction) > DB_SIZE_CRITICAL;\nconst gcpPredictionWarning = parseFloat(gcpPrediction) > DB_SIZE_CRITICAL;\n\nreturn [{\n json: {\n uat: {\n currentSize: (uatStats.database_size_mb || 0) + ' MB',\n growthRate: uatGrowthRate + '%',\n prediction6m: uatPrediction + ' MB',\n warning: uatWarning,\n predictionWarning: uatPredictionWarning\n },\n gcp: {\n currentSize: (gcpStats.database_size_mb || 0) + ' MB',\n growthRate: gcpGrowthRate + '%',\n prediction6m: gcpPrediction + ' MB',\n warning: gcpWarning,\n predictionWarning: gcpPredictionWarning\n },\n historyMonths: monthsData.length,\n hasWarning: uatWarning || gcpWarning || uatPredictionWarning || gcpPredictionWarning\n }\n}];"
|
||
},
|
||
"id": "analyze",
|
||
"name": "分析趨勢",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [900, 300]
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const data = $input.first().json;\nconst now = new Date().toLocaleString('zh-TW', { timeZone: 'Asia/Taipei' });\n\nlet message = `📈 <b>每月容量規劃報告</b>\\n\\n`;\n\nmessage += `<b>🟦 UAT 環境</b>\\n`;\nmessage += `├ 目前大小: ${data.uat.currentSize}\\n`;\nmessage += `├ 月成長率: ${data.uat.growthRate}\\n`;\nmessage += `├ 6 個月預測: ${data.uat.prediction6m}\\n`;\nif (data.uat.warning) {\n message += `└ ⚠️ 警告:接近容量上限\\n`;\n} else if (data.uat.predictionWarning) {\n message += `└ ⚠️ 預測:6 個月內可能超過容量\\n`;\n} else {\n message += `└ ✅ 容量正常\\n`;\n}\n\nmessage += `\\n<b>🟥 GCP 環境</b>\\n`;\nmessage += `├ 目前大小: ${data.gcp.currentSize}\\n`;\nmessage += `├ 月成長率: ${data.gcp.growthRate}\\n`;\nmessage += `├ 6 個月預測: ${data.gcp.prediction6m}\\n`;\nif (data.gcp.warning) {\n message += `└ ⚠️ 警告:接近容量上限\\n`;\n} else if (data.gcp.predictionWarning) {\n message += `└ ⚠️ 預測:6 個月內可能超過容量\\n`;\n} else {\n message += `└ ✅ 容量正常\\n`;\n}\n\nmessage += `\\n📊 歷史數據: ${data.historyMonths} 個月\\n`;\nmessage += `⏰ 報告時間: ${now}`;\n\nreturn [{ json: { message } }];"
|
||
},
|
||
"id": "format-report",
|
||
"name": "格式化報告",
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [1120, 300]
|
||
},
|
||
{
|
||
"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": "發送報告",
|
||
"type": "n8n-nodes-base.httpRequest",
|
||
"typeVersion": 4.2,
|
||
"position": [1340, 300]
|
||
}
|
||
],
|
||
"connections": {
|
||
"每月 1 日 08:00": {
|
||
"main": [
|
||
[
|
||
{ "node": "UAT DB 統計", "type": "main", "index": 0 },
|
||
{ "node": "GCP DB 統計", "type": "main", "index": 0 }
|
||
]
|
||
]
|
||
},
|
||
"UAT DB 統計": {
|
||
"main": [
|
||
[{ "node": "合併結果", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"GCP DB 統計": {
|
||
"main": [
|
||
[{ "node": "合併結果", "type": "main", "index": 1 }]
|
||
]
|
||
},
|
||
"合併結果": {
|
||
"main": [
|
||
[{ "node": "分析趨勢", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"分析趨勢": {
|
||
"main": [
|
||
[{ "node": "格式化報告", "type": "main", "index": 0 }]
|
||
]
|
||
},
|
||
"格式化報告": {
|
||
"main": [
|
||
[{ "node": "發送報告", "type": "main", "index": 0 }]
|
||
]
|
||
}
|
||
},
|
||
"settings": {
|
||
"executionOrder": "v1"
|
||
},
|
||
"staticData": null,
|
||
"tags": [],
|
||
"triggerCount": 0,
|
||
"updatedAt": "2026-02-07T17:00:00.000Z",
|
||
"versionId": "1"
|
||
}
|