在 `Application_Start` 啟動 `System.Timers.Timer`,可實現背景定時作業(如快取預熱、資料同步、清理過期資料)。
<%@ Import Namespace="System.Timers" %>
<script runat="server">
private static Timer _timer;
void Application_Start(object sender, EventArgs e)
{
_timer = new Timer(60000); // 60 秒
_timer.Elapsed += Timer_Elapsed;
_timer.AutoReset = true;
_timer.Enabled = true;
Application.Lock();
Application["LastRun"] = DateTime.Now;
Application.UnLock();
}
void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
Application.Lock();
Application["LastRun"] = DateTime.Now;
// 執行定時任務:同步資料、清理快取、發送郵件等
DoBackgroundWork();
Application.UnLock();
}
void Application_End(object sender, EventArgs e)
{
_timer?.Dispose();
}
void DoBackgroundWork()
{
// 實際業務邏輯
}
</script>
<%@ Page Language="C#" %>
<%= Application["LastRun"] %>
<meta http-equiv="refresh" content="10" />
| 風險 | 說明 | 對策 |
|---|---|---|
| 應用程式池回收 | IIS 預設 29 小時/閒置 20 分鐘回收,Timer 會停止 | 設定固定間隔回收、關閉閒置超時、或用 Windows Service/排程器 |
| 多執行個體 (Web Farm) | 每台伺服器各跑一份 Timer,重複執行 | 分散式鎖、或僅指定一台跑背景任務 |
| 非受控執行緒例外 | Timer 執行緒拋出未捕獲例外會終結進程 | `Elapsed` 事件內全包 `try-catch`、記錄日誌不拋出 |
| Application 鎖爭用 | 高頻寫入 `Application` 會阻塞請求執行緒 | 改用 `static` 變數 + `lock`、或 `ConcurrentDictionary` |
僅建議在**單機、低頻、非關鍵**任務(如每日靜態報表生成)使用此簡易 Timer 方案。