Администрирование Linux-серверов

Cron и systemd timers: задачи по расписанию и диагностика сбоев

Как запускать команды каждые 5 минут и по календарю через cron или systemd timer, проверять выполнение и искать причины пропусков и ошибок.

12 минут
абстрактная иллюстрация: расписание задач Linux-сервера
Cron удобен для простых записей в расписании, а systemd timer — когда задачу нужно связать со службой, зависимостями и журналом systemd. В обоих случаях планирование и успешный результат команды нужно проверять отдельно: срабатывание расписания не доказывает, что полезная операция завершилась без ошибки. Диагностика начинается с расписания и состояния планировщика, затем проверяют время сервера, окружение, журнал и результат самой команды.

Cron или systemd timer: что выбрать

Инструменты решают разные задачи; systemd timer не является универсальной заменой cron.

КритерийCronSystemd timer
Простая команда по минутному расписаниюПодходит: запись добавляют в crontab.Тоже подходит, но требует как минимум двух unit-файлов.
Журнал и статус запускаЗависят от реализации cron, syslog/journal и перенаправления вывода.Связанный service имеет статус и обычно пишет stdout/stderr в journal.
Зависимости от служб и порядок запускаНе выражаются штатной записью crontab.Можно задать средствами systemd в service и timer units.
Пропуск срока во время простояОбычно не воспроизводится после запуска демона. Для дневных периодических задач существует отдельный механизм anacron.Persistent=true для календарного таймера может инициировать один пропущенный запуск при следующей активации.
Правила сопровожденияУдобен там, где crontab уже принят как стандарт.Удобен в системах, где задачи сопровождают как units systemd.

Выбирайте cron для независимой короткой операции с прозрачным расписанием. Выбирайте timer, если важны единый журнал, состояние связанной системной службы, зависимости или контролируемая обработка одного пропущенного календарного срока. Основы управления units и systemctl разобраны в статье systemd и systemctl: управление службами и автозагрузкой Linux.

Что такое crontab и выражение cron

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

# ┌──────── минута (0–59)
# │ ┌────── час (0–23)
# │ │ ┌──── день месяца
# │ │ │ ┌── месяц
# │ │ │ │ ┌ день недели
# │ │ │ │ │
# * * * * * команда

Пользовательский crontab редактируют командой crontab -e; задача выполняется от имени этого пользователя. Системные файлы расписания часто находятся в каталогах и файлах, определённых реализацией cron и дистрибутивом. В частности, строки в типичном /etc/cron.d/имя-файла и системном crontab обычно содержат дополнительное поле пользователя между расписанием и командой. Запись из пользовательского crontab -e этого поля не содержит.

Синтаксис зависит от реализации cron

Пять временных полей характерны для распространённых реализаций, но допустимые имена месяцев и дней недели, диапазоны, переменные окружения и обработка символа % следует сверять с документацией установленного cron: обычно это man 5 crontab и документация целевой ОС. В ряде реализаций неэкранированный % в команде отделяет данные для стандартного ввода, поэтому его экранируют как \% либо выносят команду в скрипт.

Cron каждые 5 минут: самостоятельный сценарий

Создание cron-задачи с явными путями и логом

Пример предполагает, что исполняемый файл /usr/local/sbin/report.sh уже существует, а пользователь имеет права на рабочий каталог и файл лога.

  1. 1
    Подготовьте рабочий каталог и проверьте команду вручную
    Используйте абсолютные пути. Выполните ту же команду от имени пользователя, которому принадлежит crontab, а не только из своего административного сеанса. Если скрипт требует Bash, укажите это в его shebang или вызывайте /bin/bash явно; Bash и другая командная оболочка могут по-разному обрабатывать синтаксис.
  2. 2
    Создайте каталог для лога
    Например, заранее создайте /var/log/report-task и назначьте владельца, от имени которого будет работать задача. Не рассчитывайте, что cron создаст отсутствующие каталоги.
  3. 3
    Откройте пользовательский crontab
    Выполните crontab -e под нужной учётной записью. Для root используется отдельный crontab; не добавляйте поле пользователя в запись пользовательского crontab.
  4. 4
    Добавьте расписание и явный запуск
    Строка ниже меняет каталог, запускает команду абсолютным путём и добавляет stdout и stderr в один лог. Оператор && не позволит выполнить скрипт, если переход в каталог завершится ошибкой.
  5. 5
    Проверьте сохранённое расписание и результат
    Выполните crontab -l, дождитесь одного срока и проверьте время изменения лога, его содержимое и побочный результат задачи: созданный отчёт, обновлённые данные или иной ожидаемый артефакт.
пользовательский crontab
*/5 * * * * /bin/sh -c 'cd /var/lib/report && exec /usr/local/sbin/report.sh' >>/var/log/report-task/report.log 2>&1
Показывает crontab текущего пользователя. Это подтверждает сохранение записи, но не выполнение команды.
crontab -l

В распространённых реализациях cron, поддерживающих шаг /, */5 * * * * означает запуск на минутах 0, 5, 10 и далее. Это не обещает старт ровно в секунду: на фактическое время влияют реализация планировщика, нагрузка и системное время. При выключенном сервере или остановленном демоне накопившиеся пятиминутные запуски cron обычно не выполняет.

Cron запускает команду в неполном неинтерактивном окружении. Не следует ожидать тот же PATH, текущий каталог, переменные из профиля, функции и псевдонимы, что в терминале. Поэтому указывайте абсолютные пути, задавайте необходимые переменные прямо в crontab или скрипте и не полагайтесь на startup-файлы оболочки. Подробности о запуске от другого пользователя и правах — в статье Пользователи, группы, sudo и права файлов в Linux.

Вывод и почта cron

Во многих реализациях cron непустой stdout/stderr задания пытаются передать локальной почтовой подсистеме; переменная MAILTO может менять получателя или отключать такую отправку. Наличие и настройку локального MTA нельзя предполагать. Явное перенаправление, как в примере, сохраняет вывод в файле без зависимости от почтовой доставки, если каталог существует и файл удаётся открыть для записи. Поэтому отдельно проверьте владельца, права и свободное место.

Systemd timer: service и timer для существующей команды

Systemd использует именованные объекты — systemd units. Unit с суффиксом .timer обычно активирует одноимённый .service: report.timer активирует report.service. Это сопоставление можно изменить директивой Unit=, но в простом сценарии лучше сохранить одинаковую основу имени.

Календарный таймер каждые 5 минут

Пример запускает существующую команду /usr/local/sbin/report.sh от имени учётной записи report. Эта учётная запись должна существовать и иметь права на скрипт и /var/lib/report. Пути /etc/systemd/system и команды ниже типичны для системного systemd; доступность директив зависит от версии systemd.

  1. 1
    Создайте service unit
    Service описывает однократный запуск полезной команды. Системный service без User= по умолчанию запускается от root, поэтому в примере явно задан User=report. WorkingDirectory= задаёт каталог, а stdout и stderr обычно попадут в journal, если не перенаправлены иначе.
  2. 2
    Создайте связанный timer unit
    OnCalendar=*:0/5 задаёт календарные сроки на минутах 0, 5, 10 и далее каждого часа. Persistent=true позволяет при следующей активации инициировать один запуск, если календарный срок был пропущен во время неактивности таймера.
  3. 3
    Перечитайте unit-файлы
    После добавления или изменения unit выполните systemctl daemon-reload. Команда только перечитывает определения units и сама по себе не включает и не запускает таймер.
  4. 4
    Включите и запустите timer
    systemctl enable --now report.timer настраивает включение timer при загрузке и немедленно активирует сам timer. Обычно service будет ждать ближайшего календарного срока, но при Persistent=true возможен немедленный компенсирующий запуск, если после предыдущей активности таймера был пропущен срок.
  5. 5
    Проверьте расписание и выполнение
    Посмотрите ближайшее и последнее срабатывание через systemctl list-timers --all, затем проверьте состояние и журнал report.service. Для немедленной функциональной проверки можно отдельно запустить сервис вручную.
/etc/systemd/system/report.service
[Unit]
Description=Generate report

[Service]
Type=oneshot
User=report
WorkingDirectory=/var/lib/report
ExecStart=/usr/local/sbin/report.sh
/etc/systemd/system/report.timer
[Unit]
Description=Run report every five minutes

[Timer]
OnCalendar=*:0/5
Persistent=true

[Install]
WantedBy=timers.target
Перечитывает новые определения, включает timer для последующих загрузок и запускает его в текущей системе.
systemctl daemon-reload && systemctl enable --now report.timer
Показывает известные timers, включая следующие и последние срабатывания, когда эти сведения доступны.
systemctl list-timers --all
Отдельно запускает полезную команду и затем показывает состояние сервиса независимо от успешности запуска. Ручной запуск не заменяет проверку самого timer.
systemctl start report.service; systemctl status report.service

OnCalendar= задаёт календарное время. Для интервалов, отсчитываемых от загрузки или активности unit, systemd предоставляет монотонные директивы, в том числе OnBootSec= и OnUnitActiveSec=. AccuracySec= допускает объединение близких срабатываний в пределах заданной точности, а RandomizedDelaySec= добавляет случайную задержку и может снизить одновременную нагрузку от многих задач. Точный синтаксис и семантику этих директив проверяйте в официальном руководстве systemd.timer для версии systemd на сервере.

Persistent=true не воспроизводит все пропуски

Согласно документации systemd, Persistent=true относится к календарным таймерам с OnCalendar= и при следующей активации может вызвать один запуск связанного unit, если хотя бы один срок наступил в период неактивности. Он не запускает задачу по числу всех пропущенных сроков, не действует как журнал очереди и не делает операцию идемпотентной — безопасной при повторном выполнении. Доступность и детали поведения зависят от версии systemd.

Для сложных параметров service unit — пользователя, окружения, зависимостей, ограничений и перезапуска — используйте статью Как создать службу systemd для собственного приложения или скрипта. Названия директив, доступные возможности и отображаемые статусы зависят от версии systemd; сверяйте их с документацией установленной версии.

Как доказать, что задача действительно выполнилась

Запланированная задача проходит как минимум два независимых этапа: планировщик решает активировать команду, затем команда выполняет полезную работу. Состояние cron, активный timer или строка в list-timers подтверждают только часть первого этапа. Успех нужно подтверждать кодом завершения, журналом и проверкой ожидаемого результата.

  • Для cron: проверьте созданный лог, время его записи, код завершения при тестовом ручном запуске и артефакт работы команды.
  • Для systemd: проверьте systemctl status report.service, затем журнал сервиса и прикладной результат. Service типа oneshot после завершения может быть inactive, поэтому важны Result, код завершения и сообщения журнала.
  • Для операции с файлами, базой данных, резервной копией или внешним API определите собственный критерий: наличие процесса или unit со статусом active его не заменяет.

Cron не запускается: порядок диагностики

Проблема

Запись есть в crontab, но задача не выполняется или вручную работает иначе

Возможные причины

  • Редактируется не тот crontab либо запись имеет синтаксическую ошибку.
  • Демон cron не установлен, остановлен или называется иначе в данном дистрибутиве.
  • Сервер был выключен либо демон не работал в срок срабатывания.
  • Отличаются пользователь, `PATH`, текущий каталог, переменные, оболочка или права доступа.
  • Ошибка находится в самой команде, её зависимостях, сети, хранилище либо внешних ограничениях.

Решение

Сначала выполните crontab -l под нужным пользователем и проверьте поля расписания. Затем узнайте установленную реализацию cron и имя её службы по документации целевой ОС; типичные варианты имён — cron и crond, но переносить их между дистрибутивами нельзя. Проверьте статус соответствующей службы через systemctl status, найдите её записи в journal или в настроенных системных логах и сопоставьте время с ожидаемым запуском. После этого выполните точную команду от того же пользователя, с тем же каталогом и перенаправлением вывода, что в crontab. Если расписание сработало, а команда вернула ошибку, исправлять нужно команду или её окружение, а не cron.

Как избежать

Используйте абсолютные пути, явный рабочий каталог, отдельный лог stdout/stderr и проверяемый результат. После изменения проверяйте один фактический запуск.

Типовой пример просмотра журнала службы cron. Если unit называется `crond` или cron пишет в иной источник, используйте имя и способ журналирования из документации своей ОС.
journalctl -u cron --since "today"

Имя пакета, название службы, расположение системных crontab и источник логов различаются между дистрибутивами и реализациями cron. На одной системе записи могут быть в journal, на другой — в текстовом syslog-файле, если он настроен. Не делайте вывод об отсутствии запуска только потому, что нет конкретного файла лога. Подробнее о выборе источника и фильтрации записей — в статье Журналы Linux: journalctl, rsyslog и logrotate.

Диагностика systemd timer и ошибки service

Показывает timers, в том числе неактивные, их последнее и следующее срабатывание, а также unit, который они активируют.
systemctl list-timers --all
Показывает состояние timer и связанного service независимо друг от друга. Активный timer не означает успешного выполнения service.
systemctl status report.timer; systemctl status report.service
Отбирает сообщения timer и service за текущий день. [journalctl](/baza-znaniy/glossariy/journalctl) читает журнал; команда не меняет состояние units.
journalctl -u report.timer -u report.service --since "today"
  1. Убедитесь, что timer загружен и включён: проверьте systemctl status report.timer и вывод systemctl list-timers --all.
  2. Сопоставьте NEXT и LAST с текущим временем сервера. Если время или часовой пояс неверны, сначала исправьте эту причину по статье Синхронизация времени в Linux: timedatectl, chrony и проверка NTP.
  3. Проверьте, что timer активирует ожидаемый service: это видно в столбце ACTIVATES и в определении timer.
  4. Откройте systemctl status report.service и journalctl -u report.service. Ошибка ExecStart=, отсутствующий файл, неверный рабочий каталог или код завершения относятся к выполнению service, а не к календарю.
  5. После изменения .service или .timer выполните systemctl daemon-reload, затем снова проверьте конфигурацию и ближайшее срабатывание.

Время и точность расписания

И cron, и systemd зависят от системного времени. Для systemd на момент запуска также влияют AccuracySec= и, если задан, RandomizedDelaySec=. Не используйте задания по расписанию как проверку исправности NTP: причины неверного времени и настройка chrony рассматриваются отдельно в Синхронизация времени в Linux: timedatectl, chrony и проверка NTP.

Если timer срабатывает, но service имеет состояние failed или ненулевой результат, это уже диагностика службы и команды. Не стирайте первичные данные немедленным повторным запуском: сначала сохраните вывод systemctl status и записи журнала. Разбор состояний units и причин отказа — в статье Служба systemd не запускается: диагностика ошибок и восстановление. Внешними причинами также могут быть права, SELinux, сетевые ограничения, недоступность хранилища или секретов; их проверяют в профильных материалах, а не заменой расписания.

Термины в статье

Выражение cron — запись календарного расписания запуска задания. Обычный формат содержит поля минуты, часа, дня месяца, месяца и дня недели.
Демон — обычно длительно работающий неинтерактивный процесс, который в фоне выполняет системную, сетевую или прикладную функцию.
Командная оболочка — программа-интерпретатор, принимающая команды и запускающая процессы; в отличие от терминала, она обрабатывает синтаксис и сценарии.
Процесс — экземпляр выполняемой программы в Linux с PID, виртуальным адресным пространством, состоянием и связанными с ним ресурсами.
Системная служба — программный компонент, которым ОС управляет как логической единицей для фонового выполнения задач или предоставления функций программам и пользователям.
Суперпользователь — учётная запись с UID 0 или процесс с эффективным UID 0, обладающий административными правами; его полномочия шире, чем у обычного пользователя.
anacron — утилита для периодических заданий с интервалом в днях, которая при очередном запуске однократно выполняет задания, срок которых наступил во время простоя системы.
Bash — командная оболочка Unix-подобных систем, реализующая язык POSIX shell и добавляющая расширения для интерактивной работы и сценариев.
chrony — программный комплекс для синхронизации системного времени по NTP, рассчитанный в том числе на нестабильную сеть и периодические подключения.
Cron — служба-планировщик в Unix-подобных ОС, запускающая команды по расписаниям из таблиц crontab, обычно с минутной дискретностью.
crontab — таблица заданий планировщика cron, задающая команды и расписание их запуска от имени конкретного пользователя или системной учётной записи.
journalctl — консольная утилита чтения и фильтрации журнала systemd, выводящая сообщения по времени, юниту, загрузке системы, приоритету и другим полям.
NTP — сетевой протокол синхронизации системных часов с источниками точного времени, оценивающий смещение часов и сетевую задержку по временным меткам.
systemctl — командная утилита управления systemd, которая запускает и останавливает юниты, показывает их состояние и настраивает автоматическую активацию.
systemd — система инициализации и менеджер служб Linux, управляющий службами и другими ресурсами как объектами unit, обычно описанными unit-файлами.
systemd timer — юнит systemd, который по календарному или монотонному расписанию активирует другой юнит, по умолчанию одноимённый сервис.
Systemd unit — именованный объект systemd, представляющий отслеживаемый или управляемый ресурс, службу, задачу либо состояние системы.

Вопросы по теме

Все вопросы и ответы

Запустит ли cron пропущенные задачи каждые 5 минут после простоя?

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

Нужно ли указывать пользователя в записи из `crontab -e`?

Нет. В пользовательском crontab, который редактируют через crontab -e, после пяти полей расписания сразу указывают команду; задача запускается от имени владельца этого crontab. Поле пользователя требуется в типичных системных crontab и файлах /etc/cron.d/, где оно находится между расписанием и командой.

Что означает активный systemd timer, если команда не выполнилась?

Активный timer означает только, что планировщик включён, а не успешность полезной команды. Timer и связанный service проверяют отдельно: откройте systemctl status report.service, посмотрите Result и код завершения, затем изучите журнал service и прикладной результат — файл, отчёт, данные или иной ожидаемый артефакт.

Запустит ли `Persistent=true` все пропущенные срабатывания timer?

Persistent=true применяют к календарным timers с OnCalendar=. Если timer был неактивен, например во время простоя системы, и в этот период наступил хотя бы один запланированный срок, при следующей активации systemd может запустить связанный service один раз. Поэтому после systemctl enable --now report.timer возможен немедленный компенсирующий запуск.

Этот механизм не хранит очередь всех пропущенных периодов: задача не будет автоматически выполнена отдельно за каждый пятиминутный интервал. Также Persistent=true не делает операцию безопасной при повторном запуске. Если команда создаёт резервные копии, меняет данные или обращается к внешнему API, её логику нужно проектировать с учётом возможного повторного единичного запуска. Доступность и детали поведения следует сверять с документацией версии systemd на сервере.

Нужно ли экранировать символ `%` в команде cron?

Зависит от реализации cron, но обычно да. В ряде реализаций неэкранированный % в команде отделяет данные, передаваемые на стандартный ввод, поэтому команда может отработать не так, как ожидается. Экранируйте символ как \% или вынесите сложную команду в отдельный скрипт.