−25%

Windows 年繳方案適用,至 10 月 31 日。 檢視方案

EQVPS
開始使用

如何在 Windows Server 上 24/7 執行指令碼:登出、當機、重新開機都不中斷

只用工作排程器,讓機器人或指令碼在 Windows Server 2022 VPS 上日夜不停地執行:無人登入也能開機啟動,當機後一分鐘內恢復,且絕不會同時執行兩份。我們強制結束處理程序並重新開機做了驗證。

在 Windows VPS 上執行機器人的常見做法,是在 RDP 工作階段裡啟動它然後關掉視窗。這樣能一直執行,直到某次更新在凌晨 3 點重新啟動伺服器,再也沒人把它啟動起來。每台 Windows Server 都內建的工作排程器不需額外軟體就能解決。下面的設定:

  • 在開機時、任何人登入之前啟動指令碼;
  • 如果它當掉或被結束,會在一分鐘內重新啟動;
  • 絕不會同時執行兩份。

這三點我們都在 Windows Server 2022 映像檔上驗證過:結束處理程序、重新開機、計算執行個體數量。

範例指令碼

用來代替你的機器人:每 10 秒寫一行,很容易看出它是否還在執行。

New-Item -ItemType Directory -Force C:\bots | Out-Null
Set-Content C:\bots\heartbeat.ps1 -Encoding ascii -Value @'
while ($true) {
    Add-Content -Path C:\bots\heartbeat.log -Value ("{0:u} pid {1}" -f (Get-Date), $PID)
    Start-Sleep -Seconds 10
}
'@

註冊工作

在系統管理員 PowerShell 中執行:

$action   = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\bots\heartbeat.ps1' -WorkingDirectory 'C:\bots'
$atBoot   = New-ScheduledTaskTrigger -AtStartup
$everyMin = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 1)
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit ([TimeSpan]::Zero) -MultipleInstances IgnoreNew -StartWhenAvailable
Register-ScheduledTask -TaskName 'mybot' -Action $action -Trigger $atBoot, $everyMin -Settings $settings -User 'SYSTEM' -RunLevel Highest
Start-ScheduledTask -TaskName 'mybot'

各部分的作用:

  • -AtStartup 在 Windows 開機時執行機器人,不需使用者登入。
  • 每分鐘重複會每分鐘再執行一次工作。機器人還活著就什麼也不會發生;如果它掛了,就會重新啟動。
  • -MultipleInstances IgnoreNew 讓重複變得安全:發現機器人已在執行的那一次會被略過。
  • -ExecutionTimeLimit 0 取消預設的 72 小時上限,否則時間一到工作排程器會停止機器人。
  • -User 'SYSTEM' 不需密碼與工作階段即可執行。SYSTEM 在伺服器上擁有全部權限,所以只用這種方式執行你自己的程式碼。

如果是 Python,替換動作:

$action = New-ScheduledTaskAction -Execute 'C:\Program Files\Python312\python.exe' -Argument 'C:\bots\bot.py' -WorkingDirectory 'C:\bots'

我們驗證了什麼

當機。 我們用 Stop-Process -Force 結束機器人處理程序。46 秒後,每分鐘的觸發程序已經啟動新的處理程序,而且剛好只有一份。

重新開機。 我們重新啟動伺服器且沒有登入。開機 40 秒後,機器人已經在寫記錄,伺服器上沒有任何使用者工作階段。

無效的做法。 有兩樣東西看起來對,其實不對:

  1. 「如果工作失敗,每隔…重新啟動」。 我們啟用了它,結束處理程序後,工作在就緒狀態停了好幾分鐘。它針對的是工作無法啟動的情況,而不是程式之後當掉。
  2. 包裝迴圈(while ($true) { & bot; sleep 5 })。它能重新啟動當掉的機器人,但如果包裝指令碼本身掛了,子處理程序會繼續執行,下一次啟動又會拉起第二個機器人。我們最後就得到兩份,對 Telegram 機器人來說,這代表兩個處理程序在搶同一批更新。

如何檢查

Get-ScheduledTask -TaskName mybot | Select-Object TaskName, State
Get-ScheduledTaskInfo -TaskName mybot | Select-Object LastRunTime, NextRunTime
Get-Content C:\bots\heartbeat.log -Tail 5

維護時要停止它,先執行 Disable-ScheduledTask mybot(否則每分鐘的觸發程序會再次啟動它),然後停止處理程序。Enable-ScheduledTask mybot 可以恢復。

記錄

工作不會擷取輸出。讓機器人自己寫記錄(如範例所示),或在一個小的 .cmd 啟動檔中重新導向輸出,再讓 -Execute 指向這個檔案。

選哪個方案

PowerShell 或 Python 機器人幾乎不佔 CPU,但在我們的映像檔上,Windows 本身閒置時就使用 1 到 1.3 GB 記憶體。Windows-Small(4 vCPU、4 GB 記憶體、50 GB,每月 $11)適合執行一兩個機器人。在 NAT 方案上,對外連線(Telegram、交易所 API、你呼叫的 Webhook)都能正常運作。如果機器人需要接收 Webhook 或其他輸入流量,請選擇有獨立 IPv4 的 Windows Small-IP(每月 $28)。

下一步:保護 RDP;如果你偏好透過 SSH 管理機器人,安裝 OpenSSH。付款方式為 USDT、USDC 或 ETH,Windows 是使用你自有授權的 Server 2022(BYOL)。所有方案:Windows VPS。

常見問題

為什麼不直接讓指令碼在我的 RDP 工作階段裡執行?

那只能撐到某件事結束工作階段:登出、更新後重新開機或當機。關閉 RDP 視窗(中斷連線)會保留工作階段,但登出會結束其中的一切,而重新開機後沒有人登入去再次啟動它。排程工作不依賴任何工作階段。

工作排程器不是有「如果工作失敗,重新啟動」的設定嗎?

有,但在我們的測試中沒有用。我們結束指令碼的處理程序後,工作變成「就緒」並一直停在那裡。這個設定在工作無法啟動時才會作用,而不是在你的程式之後當掉時。真正把它拉回來的,是本文的重複觸發程序。

會不會同時執行兩個機器人?

用這個設定不會。工作直接執行機器人本身(沒有包裝指令碼),並使用 MultipleInstances IgnoreNew,所以機器人還活著時,每分鐘的觸發程序什麼也不做。真正會造成重複的是包裝迴圈:結束包裝指令碼後,它的子處理程序繼續執行,新的包裝指令碼又會再啟動一個。我們親眼看到了這種情況。

Python 或 Node.js 也能這樣用嗎?

可以。在 -Execute 填入直譯器,在 -Argument 填入指令碼,都用完整路徑,例如 -Execute 'C:\Program Files\Python312\python.exe' -Argument 'C:\bots\bot.py'。請為所有使用者安裝直譯器,這樣 SYSTEM 帳戶才找得到它。

評論

目前還沒有評論。歡迎成為第一位。

發表評論

評論在顯示前會經過審核。