Перейти к содержанию
Innovialabs

Cron в Linux: как правильно настроить задачи по расписанию

Практика3 мин

Коротко

Добавьте задачу через crontab -e, указывайте абсолютные пути, перенаправляйте вывод в лог и оборачивайте долгие задачи во flock, чтобы они не запускались параллельно.

Коротко: как добавить задачу

Откройте редактор своего расписания:

crontab -e

Каждая строка — это время запуска и команда:

*/15 * * * * /usr/bin/php /var/www/app/artisan schedule:run >> /var/log/app-cron.log 2>&1

Посмотреть текущие задачи: crontab -l. Большинство проблем с cron связаны не с синтаксисом, а с окружением: задача работает из терминала, но молча падает по расписанию.

Синтаксис расписания

Пять полей слева направо:

ПолеЗначения
Минута0-59
Час0-23
День месяца1-31
Месяц1-12
День недели0-7 (0 и 7 — воскресенье)

Примеры:

  • 0 3 * * * — каждый день в 03:00;
  • */10 * * * * — каждые 10 минут;
  • 0 9 * * 1-5 — в 09:00 по будням;
  • 30 2 1 * * — 1-го числа каждого месяца в 02:30;
  • 0 */6 * * * — каждые 6 часов в начале часа.

Время считается по часовому поясу сервера. Проверьте его командой timedatectl, прежде чем ставить задачи «на ночь».

Ловушка: если заданы и день месяца, и день недели, cron запускает задачу, когда совпало любое из условий, а не оба сразу.

Окружение и PATH

Cron запускает команды с минимальным окружением: короткий PATH, другая оболочка (/bin/sh), нет переменных из .bashrc и .env. Отсюда типичная ошибка «command not found».

Что делать:

  • указывайте абсолютные пути к программам и файлам (/usr/bin/node, а не node); путь можно узнать через which node;
  • задайте переменные в начале crontab:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
  • для сложной логики пишите отдельный скрипт, а в cron вызывайте только его;
  • символ % в crontab означает перевод строки — экранируйте его как \% (часто встречается в date +%F).

Логирование вывода

По умолчанию вывод задачи отправляется по почте локальному пользователю — на большинстве серверов это означает, что он теряется. Перенаправляйте вывод явно:

0 3 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1

2>&1 важно: без него ошибки (stderr) не попадут в лог. Не забудьте про ротацию этого файла, иначе он со временем займет диск. Чтобы проверить, запускался ли cron вообще, смотрите системный журнал: journalctl -u cron или grep CRON /var/log/syslog (название службы зависит от дистрибутива).

Защита от параллельных запусков

Если задача раз в 5 минут иногда работает 7 минут, запуски наложатся: двойные письма, гонки в базе, перегрузка. Простое решение — flock:

*/5 * * * * /usr/bin/flock -n /tmp/sync.lock /opt/scripts/sync.sh

Флаг -n означает: если предыдущий запуск еще держит блокировку, новый просто не стартует.

systemd timers как альтернатива

На современных дистрибутивах можно использовать systemd timers. Нужны два файла: .service (что запускать) и .timer (когда).

# /etc/systemd/system/backup.timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
cronsystemd timer
Настройкаодна строкадва файла
Логинужно перенаправлятьавтоматически в journalctl
Пропущенные запускитеряютсяPersistent=true догоняет
Параллельные запускинужен flockсервис не запустится дважды
Лимиты ресурсовнетесть (CPU, память)

Для пары простых задач cron удобнее. Для важных фоновых процессов timers дают больше контроля.

Частые ошибки

  • Относительные пути и надежда на PATH из терминала.
  • Вывод никуда не пишется, и о сбоях никто не знает.
  • Задачи в UTC, а ожидание — по местному времени.
  • Отредактировали /etc/crontab, забыв, что там есть дополнительное поле с именем пользователя.

Частые вопросы

Почти всегда дело в окружении: другой PATH, нет переменных, другая рабочая папка. Используйте абсолютные пути, задайте нужные переменные и перенаправьте вывод в лог, чтобы увидеть ошибку.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.