副標:每天凌晨自動刷新資料、定期推送訊息,還能避免重複觸發的完整範例。
問題背景與需求
- 目標: 每天凌晨自動更新台鐵站名對照表。 定時(每分鐘)自動推送訊息。 每天定時清理會員到期狀態。 避免因多次部署而產生重複觸發器。
- 限制: 使用 ScriptApp 內建觸發器 API。 時區需對應 Asia/Taipei。 Google Apps Script 免費版的觸發間隔限制。
- 輸出:一段可直接貼上專案的初始化程式碼。
💡 為什麼我會做這個? 我在開發台鐵查詢與 LINE Bot 整合服務時,需要每日更新站名資料表,也要定期推送使用者訂閱的通知。由於專案常常重新部署,若不清除舊觸發器,會造成同一事件被執行多次,增加 API 成本與錯誤風險。
架構與流程
初始化腳本(initTriggers)
├─ 清除所有舊觸發器
├─ 建立每日 03:15 更新站名的觸發器
├─ 建立每分鐘推送訊息的觸發器
├─ 清除舊的 memberExpireSweep 觸發器
└─ 建立每日 03:10 清理會員的觸發器
環境與版本
- OS:不限(雲端執行)
- Runtime:Google Apps Script(V8)
- 主要物件:ScriptApp
- API 限制:免費版每分鐘觸發最小間隔為 1 分鐘
步驟實作
檔案與路徑:/init/triggers.gsfunction initTriggers() {
// 1. 清除所有舊觸發器(避免重複)
ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t));
// 2. 每日 03:15 刷新站名對照表
ScriptApp.newTrigger('refreshStationMap')
.timeBased()
.atHour(3).nearMinute(15) // 時區以專案設定為準(Asia/Taipei)
.everyDays(1)
.create();
// 3. 每分鐘推送訊息(免費版可用)
ScriptApp.newTrigger('autoPushMessage')
.timeBased()
.everyMinutes(1)
.create();
// 4. 先清掉同名舊觸發(只針對 memberExpireSweep)
ScriptApp.getProjectTriggers()
.filter(t => t.getHandlerFunction() === 'memberExpireSweep')
.forEach(t => ScriptApp.deleteTrigger(t));
// 5. 建立每天 03:10 清理會員的觸發器
ScriptApp.newTrigger('memberExpireSweep')
.timeBased()
.atHour(3).nearMinute(10)
.everyDays(1)
.inTimezone('Asia/Taipei')
.create();
}
驗證與結果
- 在 GAS 編輯器中執行 initTriggers()。
- 打開 編輯 → 目前專案的觸發器,應會看到: refreshStationMap — 每日 03:15 autoPushMessage — 每分鐘 memberExpireSweep — 每日 03:10
常見錯誤與排錯表
訊息 可能原因 解法 觸發器重複執行 部署多次未清除舊觸發器 在建立前先 deleteTrigger 觸發時間不準 未指定時區 用 .inTimezone('Asia/Taipei') 免費版不能每秒跑 間隔低於 1 分鐘 改成 .everyMinutes(1)
延伸與 TODO
- 加入條件判斷,依據環境(測試/正式)建立不同觸發器。
- 使用 PropertiesService 儲存觸發器設定,方便版本管理。
- 自動偵測觸發器異常並重新建立。
版本資訊(Changelog)
- 2025-08-14:初稿完成,實測可在台鐵查詢專案正常運作。
工具小筆記|
- 建議將觸發器初始化腳本獨立成檔案,方便在部署時單獨執行。
- 不要在業務函式內直接建立觸發器,否則可能因使用者多次觸發而暴增。










