Запуск Python-скрипта по расписанию: cron, Task Scheduler, schedule
Три способа запускать Python-скрипт по расписанию: системный cron в Linux, Планировщик заданий в Windows и библиотека schedule внутри процесса. Что выбрать под конкретную задачу и где каждый ломается.

Задача звучит одинаково: «пусть скрипт запускается каждый день в 3 утра». Но реализаций три, и они не взаимозаменяемы. Системный планировщик (cron или Task Scheduler) запускает ваш скрипт как отдельный процесс по времени операционной системы — скрипт отработал и завершился. Библиотека schedule работает наоборот: ваш Python-процесс висит в памяти постоянно и сам решает, когда вызвать функцию. Выбор между ними определяет, переживёт ли расписание перезагрузку сервера и что случится, если задача упадёт.
Ниже — три подхода с ценой каждого, таблица сравнения и раздел о том, что ломается в проде. Версии: Python 3.11+, cron на любом современном Linux (crontab из пакета cron/cronie), Windows 10/11, библиотека schedule 1.2.x.
Подход 1. cron — системный планировщик Linux
cron запускает команды по расписанию, заданному пятью полями времени. Он не знает, что внутри Python — для него это просто команда в шелле. Плюс: расписание живёт в системе, а не в вашем процессе, и переживает перезагрузку. Минус: между запусками ничего не сохраняется — каждый запуск это чистый процесс с нуля.
Открываете таблицу заданий текущего пользователя:
crontab -e
Добавляете строку. Пять звёзд — это минута, час, день месяца, месяц, день недели. Запуск каждый день в 03:00:
# Каждый день в 3:00 запустить скрипт бэкапа
0 3 * * * /home/deploy/venv/bin/python /home/deploy/app/backup.py >> /home/deploy/logs/backup.log 2>&1
Три вещи, на которых спотыкаются все:
- Полные пути обязательны. cron запускается с урезанным окружением, где
PATHпочти пустой. Писать простоpython backup.pyнельзя — интерпретатор не найдётся. Указывайте абсолютный путь к Python из вашего виртуального окружения и абсолютный путь к скрипту. - Логи не пишутся сами. Если не перенаправить вывод, вы никогда не узнаете, отработал скрипт или упал.
>> файл.log 2>&1дописывает и обычный вывод, и ошибки в один файл. - Рабочая директория — домашняя, а не папка скрипта. Если скрипт открывает файлы по относительным путям, он их не найдёт. Внутри скрипта стройте пути от
__file__, а не полагайтесь на текущую директорию.
Проверить, что запись принята — вывести список заданий:
crontab -l
Логи самого cron о попытках запуска обычно лежат в /var/log/syslog (Debian/Ubuntu) или доступны через journalctl -u cron в системах с systemd — точный путь зависит от дистрибутива.
Подход 2. Task Scheduler — Планировщик заданий Windows
На Windows аналог cron — Планировщик заданий (Task Scheduler). Настраивается через графический интерфейс или командой schtasks. Так же, как cron, он запускает скрипт как отдельный процесс и переживает перезагрузку.
Через интерфейс: откройте «Планировщик заданий», создайте задачу, на вкладке «Действия» укажите программу и аргумент. Программа — полный путь к python.exe из вашего окружения, аргумент — путь к скрипту.
Программа/сценарий: C:\Projects\app\venv\Scripts\python.exe
Аргументы: C:\Projects\app\backup.py
Рабочая папка: C:\Projects\app
То же самое одной командой (создаёт ежедневную задачу на 03:00):
schtasks /create /tn "BackupJob" /tr "C:\Projects\app\venv\Scripts\python.exe C:\Projects\app\backup.py" /sc daily /st 03:00
Точные ключи schtasks и их варианты сверяйте через schtasks /create /? — набор параметров зависит от версии Windows.
Подводные камни Windows отличаются от cron:
- Обязательно заполните «Рабочую папку». В интерфейсе это отдельное поле «Начинать в» на вкладке «Действия». Без него скрипт стартует из
C:\Windows\System32, и относительные пути ломаются. - Запуск, когда пользователь не залогинен. По умолчанию задача может ждать входа в систему. В свойствах задачи выберите «Выполнять для всех пользователей» / «Выполнять вне зависимости от входа пользователя», иначе ночью на сервере без активной сессии ничего не запустится.
- Кодировка вывода. Консоль Windows и Python по умолчанию могут расходиться в кодировке — русский текст в логах превращается в мусор. Задайте
PYTHONUTF8=1в переменных окружения задачи или пишите логи явно в UTF-8.
Подход 3. schedule — расписание внутри процесса
Библиотека schedule не трогает систему. Вы описываете расписание прямо в Python, а процесс крутится в бесконечном цикле и сам вызывает функции в нужное время. Установка:
pip install schedule
Минимальный рабочий пример на schedule 1.2.x:
import schedule
import time
import logging
logging.basicConfig(
filename="job.log",
level=logging.INFO,
format="%(asctime)s %(message)s",
encoding="utf-8", # доступно в Python 3.9+
)
def sync_orders():
logging.info("Начали синхронизацию заказов")
# здесь основная работа
logging.info("Синхронизация завершена")
# Каждый день в 3:00
schedule.every().day.at("03:00").do(sync_orders)
# Каждые 15 минут
schedule.every(15).minutes.do(sync_orders)
while True:
schedule.run_pending()
time.sleep(1)
Важное про schedule, что не всегда очевидно из примеров в сети:
- Он не запускает процесс — он его использует. Пока Python-процесс жив, расписание работает. Убьёте процесс или перезагрузите машину — расписание исчезнет. Само оно не восстановится.
- Задачи выполняются в том же потоке. Если
sync_ordersработает 10 минут, всё это время цикл занят, и другие задачи, попавшие на это время, сдвинутся. schedule однопоточен по умолчанию. - Пропущенные запуски не навёрстываются. Если процесс лежал в 03:00, задача на 03:00 просто не выполнится — она не сработает при следующем запуске «задним числом».
cron и Task Scheduler отвечают на вопрос «когда» силами операционной системы. schedule отвечает на него силами вашего процесса — и живёт ровно столько, сколько живёт процесс.
Что выбрать
| Критерий | cron | Task Scheduler | schedule |
|---|---|---|---|
| ОС | Linux/macOS | Windows | любая |
| Переживает перезагрузку | да | да | нет |
| Состояние между запусками | нет | нет | да, в памяти процесса |
| Настройка | текстовая, вне кода | GUI или schtasks | в коде Python |
| Изоляция запусков | полная (новый процесс) | полная | общий процесс |
| Минимальный интервал | 1 минута | ~1 минута | до секунд |
Практический критерий
- Задача редкая (раз в час, раз в день), сервер Linux, нужно надёжно и без лишних зависимостей — cron.
- То же самое, но машина на Windows — Task Scheduler.
- Нужны интервалы в секунды, задача часть уже работающего долгоживущего приложения (бот, воркер), между запусками нужно держать состояние в памяти — schedule.
- Нужны надёжность, история запусков, повторы при сбое, распределение по нескольким машинам — ни один из трёх, смотрите в сторону APScheduler с хранилищем задач или Celery beat. Это отдельная тема, здесь её не разворачиваем.
Что ломается в проде
Наложение запусков. Задача запускается каждые 5 минут, но однажды отработала 7 минут. cron и Task Scheduler честно запустят вторую копию поверх первой — и вы получите два процесса, дерущихся за одну базу. Защита — файловая блокировка (lock-файл или flock в обёртке команды cron), которая не даёт второму экземпляру стартовать, пока жив первый.
Молчаливое падение. Скрипт упал с исключением, cron ничего не сообщил — вы узнаёте через неделю, что бэкапов нет. Логируйте не только успех, но и факт запуска, и оборачивайте тело в try/except с записью трейсбека. Отдельно полезен «сторож», который проверяет, что задача отметилась в логе за последние N часов.
Часовой пояс. cron работает по времени сервера, а не по вашему. Сервер в UTC, а вы ждали 03:00 по Москве — скрипт запустится в 06:00 по вашим часам. Проверьте timedatectl на сервере и держите в голове разницу. У schedule .at() тоже опирается на локальное время процесса.
Виртуальное окружение. Самая частая причина «у меня же работало в консоли». В консоли вы активировали venv, а cron — нет. Всегда указывайте полный путь к интерпретатору из venv, а не системный python.
Что делать дальше
Запустите выбранный вариант и первым делом проверьте не расписание, а логи: отработал ли скрипт хотя бы раз и что он написал. Добавьте lock-файл, если интервал короче времени выполнения задачи. Если задач становится больше пяти или нужны повторы при сбое и веб-панель со статусами — переходите на APScheduler или Celery beat: они дают персистентное хранилище задач и историю запусков, которых у cron и schedule нет из коробки.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: schedule — официальная документация, crontab(5) — man-страница формата crontab
Частые вопросы
У меня другая версия schedule — код будет работать?
Скрипт работает в консоли, но по cron не запускается. Что не так?
Как не дать двум копиям скрипта запуститься одновременно?
Что будет, если сервер был выключен в момент запланированного запуска?
Почему в логах вместо русского текста непонятные символы?
Можно ли запускать по секундам, а не по минутам?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.