核心設定:讓腳本脫離瀏覽器獨立執行
<?php
ignore_user_abort(true); // 關閉瀏覽器仍持續執行
set_time_limit(0); // 移除執行時間限制(0 表無限制)
固定間隔執行迴圈範例
$interval = 60 * 30; // 每 30 分鐘執行一次
do {
// ====== 這裡放入實際業務邏輯 ======
// 例如:資料同步、報表產生、快取清理、郵件發送等
// ===================================
sleep($interval); // 休眠等待下一輪
} while (true);
關鍵風險與改善方向
| 風險 | 說明 | 建議方案 |
| 記憶體洩漏 | 長期運行累積記憶體導致 OOM | 定期重啟、使用生成器、及時 unset 大變數 |
| 單點故障 | 腳本掛掉無自動恢復 | Systemd/Supervisor 監控自動重啟 |
| 並發衝突 | 多實例同時執行造成資料不一致 | 檔案鎖/資料庫鎖/Redis 分散式鎖 |
| 執行時間漂移 | sleep 不精確導致間隔偏移 | 計算下次執行時間點精確 sleep |
| 無優雅關閉 | 收到 SIGTERM 直接中斷 | 註冊 pcntl_signal 處理訊號 |
生產環境推薦架構
- 系統排程器:Linux
cron / Windows Task Scheduler(最簡單可靠)
- 工作佇列:Redis + PHP Worker / Laravel Horizon / Gearman
- 進程管理器:Supervisor 管理常駐 PHP 進程
- 容器化:Kubernetes CronJob 定時啟動容器執行任務
改良版迴圈(含訊號處理與精確間隔)
<?php
declare(ticks = 1);
$shutdown = false;
pcntl_signal(SIGTERM, function() use (&$shutdown) { $shutdown = true; });
pcntl_signal(SIGINT, function() use (&$shutdown) { $shutdown = true; });
ignore_user_abort(true);
set_time_limit(0);
$interval = 1800; // 30 分鐘
$nextRun = time() + $interval;
while (!$shutdown) {
$start = microtime(true);
// 業務邏輯
doTask();
// 精確計算下次執行時間
$elapsed = microtime(true) - $start;
$sleepTime = max(1, $interval - $elapsed);
sleep((int)$sleepTime);
usleep(($sleepTime - (int)$sleepTime) * 1_000_000);
}
function doTask() {
// 實際任務邏輯
}