−25%

на річну оплату Windows, до 31.10. До тарифів

EQVPS
Почати

Як запустити скрипт 24/7 на Windows Server: переживає вихід, падіння та перезавантаження

Бот або скрипт цілодобово на VPS з Windows Server 2022 лише засобами Планувальника завдань: старт під час завантаження без входу користувача, перезапуск протягом хвилини після падіння і ніколи двох копій. Ми вбивали процес і перезавантажували сервер, щоб перевірити.

Звичайний спосіб запустити бота на 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 майже не навантажує процесор, але сама Windows у простої займає на нашому образі від 1 до 1,3 ГБ пам'яті. Windows-Small (4 vCPU, 4 ГБ пам'яті, 50 ГБ, $11/міс) — відповідний розмір для одного-двох ботів. На тарифі з NAT вихідні підключення (Telegram, API бірж, виклики вебхуків) працюють як звичайно. Якщо бот має приймати вебхуки або інший вхідний трафік, беріть Windows Small-IP ($28/міс) із власним IPv4.

Далі: захистіть 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 його знайшов.

Коментарі

Поки немає коментарів. Будьте першим.

Залишити коментар

Коментарі проходять модерацію перед публікацією.