Запуск по расписанию: 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 надёжно крутит задачи силами ОС. Любой планировщик внутри — это сравнение времени с расписанием. Дальше сделаем запуски устойчивыми к ошибкам через логи и обработку исключений.

Проверьте себя
1. В чём ключевое отличие cron от библиотеки schedule?
Acron работает только на Windows
Bschedule требует живого Python-процесса, а cron запускает скрипт силами ОС
Ccron не умеет повторять задачи
Dschedule надёжнее на сервере
2. Почему в cron важно указывать абсолютные пути?
AТак быстрее запускается
Bcron запускает команду из своей рабочей папки, и относительные пути не найдутся
CАбсолютные пути короче
DЭто требование Python