Запуск по расписанию: schedule и cron
Автоматизация становится по-настоящему «авто», когда запускается без вас. Библиотека schedule описывает правила запуска человеческим языком, а cron надёжно крутит скрипты в фоне на сервере.
Суть:schedule— правила вида «каждый день в 9:00» прямо в коде; нужен живой процесс.cron— системный планировщик ОС, надёжнее для продакшена.
До сих пор мы запускали скрипты руками. Но цель автоматизации — чтобы отчёт уходил каждое утро сам. Есть два пути. Библиотека schedule (ставится как pip install schedule) позволяет описать расписание прямо в Python почти словами: «каждый день в 9 утра делай это». Минус — нужен постоянно работающий процесс, который крутит цикл.
Логику «пора ли запускать задачу» можно полностью смоделировать на datetime в браузере — именно так под капотом решает любой планировщик: сравнивает текущее время с расписанием.
Попробуй сам ▶
from datetime import datetime, timedelta
# Задачи: имя -> час запуска
jobs = {'backup': 2, 'report': 9, 'cleanup': 23}
def due_jobs(now):
return [name for name, hour in jobs.items()
if now.hour == hour and now.minute == 0]
# Прогоним сутки по часам и посмотрим, что и когда сработает
start = datetime(2026, 6, 22, 0, 0)
for h in range(24):
moment = start + timedelta(hours=h)
fired = due_jobs(moment)
if fired:
print(moment.strftime('%H:%M'), '-> запускаю:', ', '.join(fired))Видно ядро планировщика: на каждый «тик» он проверяет, совпало ли время с правилом. Библиотека schedule прячет этот цикл за красивым синтаксисом. Её код требует живого процесса и реальных задач, поэтому показан как нерабочая в браузере врезка.
import schedule, time
def daily_report():
print('Собираю и отправляю отчёт...')
# Правила почти словами
schedule.every().day.at('09:00').do(daily_report)
schedule.every().monday.at('08:00').do(weekly_summary)
schedule.every(30).minutes.do(check_mail)
# Живой цикл: проверяет расписание каждую минуту
while True:
schedule.run_pending()
time.sleep(60)Для надёжного продакшена чаще берут cron — встроенный планировщик Unix. Он сам запускает ваш скрипт по расписанию, и не нужно держать вечный Python-цикл. Строка cron — это пять полей времени.
# crontab -e открывает редактор расписаний
# мин час день месяц день_недели команда
0 9 * * * /path/.venv/bin/python /path/report.py
0 2 * * * /path/.venv/bin/python /path/backup.py
*/30 * * * * /path/.venv/bin/python /path/check.pyДВА СПОСОБА ЗАПУСКА schedule (в коде) cron (в ОС) ----------------- ----------- while True: sleep vs ОС сама будит скрипт нужен живой процесс процесс не нужен удобно локально надёжно на сервере расписание -> запуск -> скрипт -> лог результата
Какой бы планировщик вы ни выбрали, отдельно стоит подумать о ситуации, когда запуск «пропущен» — сервер был выключен в момент, на который намечена задача. Простой cron в этом случае просто не запустит задачу и не вспомнит о ней; если пропуск критичен (например, это ежедневный бэкап), нужны более умные планировщики или защитная логика, которая при следующем запуске проверит, не пропущен ли предыдущий. Ещё важнее не допускать наложения запусков: если задача иногда работает дольше своего интервала, два её экземпляра могут запуститься одновременно и помешать друг другу. Защищаются от этого файлом-блокировкой, который второй экземпляр видит и вежливо завершается.
Как работает под капотом
Библиотека schedule просто хранит список заданий с временем и при каждом run_pending() сверяет их с текущим временем — ровно как наша функция due_jobs выше. Поэтому ей нужен вечный цикл с sleep: если процесс умрёт, расписание перестанет работать.
cron устроен иначе и надёжнее: это служба самой операционной системы, которая читает таблицу crontab и сама запускает указанные команды в нужный момент. Скрипту не нужно «жить» — cron поднимет его, дождётся завершения и забудет до следующего раза. Поэтому на серверах для регулярных задач выбирают cron.
Частые ошибки
- Полагаться на schedule без живого процесса. Закрыли терминал — расписание умерло. Для сервера это не подходит.
- Относительные пути в cron. cron запускает скрипт из своей папки; пути и интерпретатор указывайте абсолютные.
- Не логировать запуски. Если cron-задача молча упала, вы узнаете об этом, когда отчёт не придёт. Пишите логи.
Best practices
- Для локальных и временных задач берите schedule, для продакшена — cron.
- В cron указывайте абсолютный путь к python из venv и к скрипту.
- Перенаправляйте вывод задачи в лог-файл, чтобы видеть историю запусков.
Итоги. schedule даёт читаемые правила в коде, но требует живого процесса; cron надёжно крутит задачи силами ОС. Любой планировщик внутри — это сравнение времени с расписанием. Дальше сделаем запуски устойчивыми к ошибкам через логи и обработку исключений.