Перейти к содержимому

Крон что это в программировании

  • автор:

Cron Jobs — пособие для начинающих

Cron — один из часто используемых инструментов для Unix-систем. Учимся писать задания в Cron вручную и с помощью простых и удобных веб-инструментнов.

Обложка поста Cron Jobs — пособие для начинающих

Cron — один из часто используемых инструментов для Unix-систем. Его используют для планирования выполнения команд на определённое время. Эти «отложенные» команды или задания принято называть «Cron Jobs». Такой инструмент отлично подходит для регулярных бэкапов, мониторинга дискового пространства, удаления файлов (например, логов) и много чего ещё. В этой статье будет рассказано о работе с Cron на Linux.

Введение

Шаблон задания для Cron выглядит примерно так:

Минуты(0-59) Часы(0-24) День(1-31) Месяц(1-12) День недели(0-6) Команда 

Вот иллюстрация этого же шаблона, которую можно сохранить себе:

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Звёздочками обозначены конкретные блоки времени.

Для отображения содержимого crontab-файла текущего пользователя используйте команду:

$ crontab -l 

Для редактирования заданий пользователя есть команда:

$ crontab -e 

Если эта команда выполняется в первый раз, вам предложат выбрать редактор для Cron:

no crontab for sk - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano 

Выбирайте на своё усмотрение. Вот так изначально выглядит crontab-файл:

В этом файле как раз нужно перечислять одну за другой все команды.

Чтобы изменить crontab-файл другого пользователя (например, ostechnix):

$ crontab -u ostechnix -e 

Ниже приведены несколько примеров cron-заданий:

  1. Чтобы выполнять команду каждую минуту, задание должно быть такое:* * * * *
  2. Похожее задание, только команда будет вызываться каждые пять минут:*/5 * * * *
  3. Вызывать команду 4 раза в час (каждые 15 минут):*/15 * * * *
  4. Чтобы выполнить команду каждый час в 30 минут, пишем:30 * * * * Т. е. команда будет выполняться не каждые 30 минут, а тогда, когда значение минут будет равно 30 (например, 10:30, 11:30, 12:30 и т. д.).
  5. Значения времени можно комбинировать, перечислив их через запятую. Следующий код будет выполнять команду три раза в час: в 0, 5 и 10 минут.0,5,10 * * * *
  6. Выполнять команду каждый час будет следующее задание:0 * * * *
  7. Выполнение команды каждые два часа:0 */2 * * *
  8. Чтобы выполнять команду каждый день (в 00:00):0 0 * * *
  9. Выполнение команды каждый день в 03:00:0 3 * * *
  10. Выполнение команды каждое воскресенье (sunday):0 0 * * SUN
  11. Другой вариант задания, которое будет выполнять команду каждое воскресенье (естественно, тоже в 00:00):0 0 * * 0
  12. Выполнение команды каждый день с понедельника по пятницу:0 0 * * 1-5
  13. Следующее задание будет выполнять команду каждый месяц, 1-го числа в 00:00:0 0 1 * *
  14. Выполнять команду в 16:15 каждого первого числа месяца будет это задание:15 16 1 * *
  15. Выполнение команды каждые три месяца:0 0 1 */3 *
  16. Выполнение команды в строго определённое время и месяц:5 0 * 4 *
  17. Задание будет вызывать команду в начале каждого полугодия (в 00:00 1-го дня):0 0 1 */6 *
  18. Выполнение команды каждый год 1-го января в 00:00:0 0 1 1 *

Ещё существуют готовые задания:

  • @reboot — одиночное выполнение команды при загрузке;
  • @yearly — раз в год;
  • @annually — тоже раз в год;
  • @monthly — раз в месяц;
  • @weekly — один раз в неделю;
  • @daily — раз в день;
  • @midnight — тоже раз в день;
  • @hourly — раз в час.

Чтобы выполнять команду каждый раз после перезапуска сервера, используйте это задание:

@reboot

Команда для очистки всех заданий текущего пользователя:

$ crontab -r 

Чтобы узнать о подробностях, есть команда:

$ man crontab 

Вышеперечисленного уже должно хватить для базовой работы с Cron и составления заданий.

Синтаксис crontab-генераторов

Процесс написания заданий сильно упрощают веб-инструменты. Они не требуют знаний синтаксиса Cron, потому что у них графический интерфейс, а задания генерируются в соответствии с вводимыми данными. Сайт генерирует задание, которое можно будет просто скопировать и вставить в crontab-файл.

Crontab.guru

crontab.guru — отличный сайт, чтобы изучить различные примеры cron-заданий. Просто введите данные и сайт самостоятельно сгенерирует конечное задание.

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

На сайте есть разделы, посвящённые примерам и советам.

Crontag Generator

crontab-generator.org — ещё один сайт, который помогает быстро сгенерировать crotab-выражения. Принцип такой же: нужно ввести все необходимые данные в формы и нажать кнопку «Generate Crontab Line» внизу страницы.

На данный момент этот блок не поддерживается, но мы не забыли о нём! Наша команда уже занята его разработкой, он будет доступен в ближайшее время.

Вот такое конечное выражение вы увидете на сайте:

Помимо этого, есть веб-инструмент «Crontab UI», который обеспечивает не только простоту создания crontab-заданий, но и безопасность. Вот статья, посвящённая этому инструменту.

Cron: что это такое и как его правильно использовать

Cron

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

Что такое Cron и crontab?

Если в двух словах, то Cron – это планировщик задач. Если подробнее, то это утилита, позволяющая выполнять скрипты на сервере в назначенное время с заранее определенной периодичностью.

К примеру, у вас есть скрипт, который собирает какие-либо статистические данные каждый день в 6 часов вечера. Такие скрипты называют «заданиями», а их логика описывается в специальных файлах под названием сrontab.

crontab – это таблица с расписанием запуска скриптов и программ, оформленная в специальном формате, который умеет считывать компьютер. Для каждого пользователя системы создается отдельный crontab-файл со своим расписанием. Эта встроенная в Linux утилита доступна на низком уровне в каждом дистрибутиве.

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

Для чего обычно используют Cron?

Обычно Cron заставляют повторять вполне очевидные задачи в духе регулярного создания резервных копий данных. Но это не все.

  1. Некоторые пользователи с помощью планировщика корректируют системное время. На многих компьютерах оно настраивается через Network Time Protocol. А так как этот протокол настраивает только время ОС, время, установленное для «железа», может отличаться. Cron позволяют регулярно корректировать время, установленное для аппаратного обеспечения, в соответствии со временем ОС.
  2. Еще один популярный сценарий – создание оповещений, появляющихся каждое утро и рассказывающих о состоянии компьютера. В эти сообщения может входить любая полезная для пользователя информация.
  3. Cron иногда работает даже без ведома пользователя. Эту утилиту используют такие сервисы, как Logwatch, logrotate и Rootkit Hunter. Повторяющиеся задачи они настраивают, как и пользователи, через Cron.

С помощью Cron пользователи автоматизируют самые разные задачи, сокращая вмешательство системного администратора в работу сервера.

Базовые принципы работы с Cron и crontab (через панель управления)

Многие хостинг-провайдеры предлагают отдельное меню в панели управления для настройки расписания запланированного выполнения скриптов.

Разберем подобное меню на примере панели управления Timeweb. Чтобы создать новую задачу, необходимо открыть раздел Crontab в боковой панели веб-интерфейса, кликнуть по кнопке «Добавить новую задачу» и указать параметры повторяющейся команды.​ Поговорим подробнее о параметрах.

  • Сначала надо придумать для команды название (подойдет любой текст без спецсимволов).
  • Затем указываем исполнителя (нужно выбрать, будет ли планировщик работать с исполняемым файлом, PHP-скриптом или HTTP-запросом).
  • В графе «Путь до файла» вводим абсолютный путь до скрипта, запуск которого хотим запланировать. К примеру: /home/u/myusername/mytestscript.php. При желании можно воспользоваться встроенным файловым менеджером и выбрать заранее предзагруженный на сервер скрипт.
  • После этого указываем периодичность выполнения выбранного скрипта или исполняемого файла (в списке доступны предустановки в духе «Каждую минуту» или «Раз в день», но можно выбрать и пункт «Продвинутые настройки»).
  • Кликаем по кнопке «Создать задачу».

На этом все. Скрипт запланирован и будет регулярно повторяться.

Cron

Базовые принципы работы с Cron и crontab (через SSH-протокол)

Планировать задачи через панель управления удобно, но не всегда возможно. Не все хостинг-провайдеры предлагают такие функциональные веб-интерфейсы. В этом случае придется воспользоваться командной строкой, подключившись к серверу по протоколу Secure Shell.

Для работы с планировщиком в системе есть ряд команд, помогающих решать основные задачи:

  • crontab -e – открывает конфигурационный файл (поговорим о нем чуть подробнее в разделе с первичной настройкой).
  • crontab -l – показывает список задач из конфигурационного файла (все, что было запланировано).
  • crontab -r – удаляет конфигурационный файл вместе со всеми запланированными задачами.
  • сrontab -v – показывает, когда в последний раз открывался конфигурационный файл.

Чтобы запланировать задачи, используя командную строку, необходимо выполнить базовую настройку Cron, проверить, не установлены ли ограничения, и заполнить расписание задач в соответствии с синтаксисом сrontab.

Первичная настройка Cron

Как мы уже выяснили ранее, планировщик черпает параметры для выполнения своих задач из crontab-файлов (таблиц с расписанием). У каждого пользователя, включая root, должен быть свой crontab-файл. По умолчанию он не существуют, поэтому придется создать его вручную.

Для этого существует команда crontab -e. Она автоматически генерирует таблицу в директории /var/spool/cron.

Вновь созданный файл будет пустым текстовым полем. Необходимо добавлять в него все параметры самостоятельно с нуля, опираясь на синтаксис сrontab (более подробно поговорим о нем ниже). После ввода параметров нужно сохранить параметры редактора, нажав на клавишу F2, а затем покинуть конфигурационный файл, нажав на клавишу F10. При введении корректных параметров в терминале отобразится строка crontab: installing new crontab.

Опытные разработчики и системные администраторы не рекомендуют использовать для редактирования расписания текстовые редакторы в духе Nano, Emacs или Vi. Команды crontab позволяют не только внести изменения в таблицу запланированных задач, но и перезапустить фоновый процесс crond, отвечающий за работу утилиты после сохранения настроек.

Ограничения Cron

У Cron есть функция установки ограничений на использование, задающихся через два специальных файла: cron.allow и cron.deny.

Первый файл находится в директории /usr/lib/cron/cron.allow и содержит в себе список учетных записей (имен пользователей), которые имеют право на планирование задач с помощью встроенных системных утилит.

Второй файл находится в директории /usr/lib/cron/cron.deny. В нем указываются имена пользователей, которые не могут запускать встроенный в систему планировщик задач.

Если первого файла не существует, то любой пользователь может планировать задачи с помощью встроенного в систему планировщика, но только при условии, что его имени нет во втором файле. Если удалить оба файла, то каждый пользователь сможет планировать задачи без ограничений.

Комьюнити теперь в Телеграм
Подпишитесь и будьте в курсе последних IT-новостей

Синтаксис crontab

# crontab -e SHELL=/bin/bash MAILTO=mymail@someprovider.com PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin # Детали смотрите в следующих разделах # Примеры оформления задач в планировщике (формат данных): # .---------------- минуты (0 - 59) # | .------------- часы (0 - 23) # | | .---------- дни месяца (1 - 31) # | | | .------- сами месяцы (1 - 12) OR jan,feb,mar,apr . # | | | | .---- дни недели (0 - 6) (0 или 7 это воскресенье в зависимости от настроек системы) можно использовать сокращения типа mon,tue,wed,thu,fri,sat,sun # | | | | | # * * * * * имя пользоваться команда, которую нужно запустить # создание копии всей операционной системы с помощью кастомного скрипта 01 01 * * * /usr/local/bin/bckp -vbd1 ; /usr/local/bin/bckp -vbd2 # установка соответствия между временем операционной системы и "железа" 03 05 * * * /sbin/hwclock --systohc # проведение обновления операционной системы в заданный период времени 25 04 1 * * /usr/bin/apt-get update

Первые три линии кода в таблице отвечают за первичную настройку. Сначала указывается оболочка, в которой будет работать Cron. У утилиты нет каких-либо предпочтений, поэтому можно указать любую на собственное усмотрение (в нашем примере это bash). Затем указывается адрес электронный почты, на который будут отправляться отчеты о работе планировщика. И напоследок указывается путь к окружению.

Ниже находятся параметры, используемые для запуска процессов в определенный период времени. В комментариях описан базовый синтаксис, включающий в себя формат времени, имя пользователя и команду, которая должна быть запущена.

В нашем случае указаны команды:

02 04 5 * * /usr/local/bin/bckp -vbd1 ; /usr/local/bin/bckp -vbd2 04 06 * * * /sbin/hwclock –systohc 10 05 5 * * /usr/bin/apt-get update 05 * * * * rm /home/myusername/tmp/*

Примеры использования Cron в командной строке

02 04 5 * * /usr/local/bin/bckp -vbd1 ; /usr/local/bin/bckp -vbd2

создает в таблице расписания задачу на запуск скрипта под названием bckp (представим, что такой существует), который создает резервную копию всей системы на стороннем накопителе. Он выполняется 5 числа каждого месяца в 4 часа 2 минуты утра. Это видно по числовым значениям. Звездочки же указывают на отсутствие конкретного значения. Cron воспринимает их как «выполнять каждый раз», то есть каждый месяц, день или неделю.

04 06 * * * /sbin/hwclock –systohc

меняет время аппаратного обеспечения на то, что используется в системе. Делает это каждый день, каждую неделю и каждый месяц в 6 часов 4 минуты утра. Как видите, здесь пропущено третье значение. Поэтому команда и запускается ежедневно, так как нет более конкретных правил.

10 05 5 * * /usr/bin/apt-get update

запускает обновление пакетов с помощью пакетного менеджера apt каждый месяц 5 числа в 05:10.

05 * * * * rm /home/myusername/tmp/*

удаляет содержимое папки с временными файлами для конкретного пользователя (меня) на пятой минуте (первый пункт) каждого часа. Так как определенные значения отсутствуют для всех остальных пунктов, получается, что скрипт готов выполняться каждый день, каждый месяц и каждый час. Но первое значение указано, поэтому он будет дожидаться пятой минуты и запускаться в этот момент. То есть в 12:05, 13:05, 14:05 и т.п.

Как видите, разобраться с базовыми командами несложно.

Другие примеры настройки Cron

На примере команды для удаления временных файлов разберем пару-тройку нестандартных настроек расписания.

К примеру, некоторые показатели можно вводить не в виде цифр, а в виде сокращенных слов. Чтобы запускать удаление временных файлов каждую пятницу в 4 часа вечера, необходимо ввести в crontab:

00 16 * * Fri rm /home/myusername/tmp/*

Если не указывать в планировщике точных вводных, то выбранный скрипт будет выполняться каждую минуту:

* * * * * rm /home/myusername/tmp/*

Можно заставить планировщик выполнять задачу только в определенные месяцы. Чтобы запускать удаление временных файлов 1 февраля, 1 мая и 1 сентября в половину первого ночи, необходимо ввести в crontab:

30 00 1 2,5,9 * * rm /home/myusername/tmp/*

Некоторые скрипты необходимо выполнять только по будням, поэтому в Cron есть возможность исключить некоторые дни недели из расписания:

00 16 * * 1–5 rm /home/myusername/tmp/*

Часы тоже можно делить. Например, запускать ту или иную задачу каждые 3 часа. Для этого нужно поставить слэш в графе с установкой времени по часам:

*/5 */2 * * * rm /home/myusername/tmp/*

Вместо заключения

О работе с Cron стоит знать еще пару важных вещей.

Во-первых, всегда указывайте корректный почтовый адрес в параметрах. Это позволит собирать информацию о запускаемых по расписанию задачах. В этих письмах содержится и информация о возникающих ошибках. Во-вторых, при указании «исполнителя» в панели управления Timeweb важно делать корректный выбор, чтобы он соответствовал запускаемой задаче. В-третьих, информацию о работе Cron можно собирать в отдельный файл с помощью команд в духе:

30 18 * * * rm /home/myusername/tmp/* > /home/myusername/cronlogs/clean_tmp_dir.log

На этом все. Следуйте инструкциям, не путайте порядок параметров и внимательно изучайте журнал ошибок, если что-то пойдет не так. После недолгой практики вы поймете, что работать с Cron не так уж и сложно!

Установка задачи для планировщика

В момент запука внутреннего планировщика cron.php в ReadyScript генерируется событие с названием "cron". Таким образом все подписчики на это событие получают по очереди возможность выполнить собственный код. Каждый обработчик события самостоятельно решает необходимо ли ему выполнять задание во время запуска или нет, опираясь на поступившие в событие параметры. В событие передается массив с тремя параметрами:

  • last_time - число, timestamp предыдущего запуска
  • current_time - число, timestamp текущего запуска
  • minutes - массив, номер минуты текущего запуска + список номеров минут для которых был пропущен запуск.

Рассмотрим различные примеры запуска cron.php:

  1. cron.php запускается первый раз за всю историю, 26.01.2016 в 16:00:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453813140 (26.01.2016 15:59:00)
    • current_time = 1453813200 (26.01.2016 16:00:00)
    • minutes = [960]
  2. cron.php запускается 26.01.2016 в 16:01:00, предыдущий запуск был 26.01.2016 16:00:00. Обработчики получат следующие параметры:
    • last_time = 1453813200 (26.01.2016 16:00:00)
    • current_time = 1453813260 (26.01.2016 16:01:00)
    • minutes = [961]
  3. cron.php запускается 26.01.2016 в 16:10:00, предыдущий запуск был 26.01.2016 16:01:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453813260 (26.01.2016 16:01:00)
    • current_time = 1453813800 (26.01.2016 16:10:00)
    • minutes = [962,963,964,965,966,967,968,969,970]
  4. cron.php запускается в 27.01.2016 00:00:00, предыдущий запуск был 26.01.2016 23:58:00. Обработчикам будут переданы следующие параметры:
    • last_time = 1453841880 (26.01.2016 23:58:00)
    • current_time = 1453842000 (27.01.2016 00:00:00)
    • minutes = [1439,0]

Как видно на примере N3, обработчик все равно получит все минуты в массиве, которые бы он получил, если бы cron запускался ежеминутно.

Три параметра, передаваемые обработчику позволяют легко организовывать любое расписание для запуска, будь то фиксированная дата или интервал. В сутки обработчики гарантировано получат в параметре minutes числа от 0 до 1439, что соответствует количеству минут в сутках.

Планировщик построен таким образом, что при любом количестве запусков файла crop.php в сутки, внутри ReadyScript все модули будут получать необходимые сведения для выполнения задач, как если бы планировщик выполнялся, как положено, раз в минуту. Если планировщик не был запущен в назначенное время, то задача выполнится при следующем выполнении cron.php.

Следует учитывать, что выполнение задания может занимать время, превышающее 1 минуту, соответственно следующий запуск планировщика будет выполнен только после полного завершения текущей сессии выполнения планировщика. Для защиты от двойного запуска, планировщик создает файл с именем cron в папе /storage/locks/. Данный файл автоматически удаляется в случае успешного завершения планировщика.

Теперь рассмотрим на примерах различные случаи формирования расписаний.

  • Необходимо установить запуск задания один раз в пять минут.

Cron — лучшие практики

Планировщик задач cron(8) существует с 7 версии Unix, а его синтаксис crontab(5) знаком даже тем, кто нечасто сталкивается с системным администрированием Unix. Это стандартизированный, довольно гибкий, простой в настройке и надёжно работающий планировщик, которому пользователи и системные пакеты доверяют управление важными задачами. Материалом о лучших практиках работы с cron делимся к старту курса по Fullstack-разработке на Python.

У простоты cron(8), как и многих старых Unix-инструментов, есть недочёт: программа полагается на то, что пользователь хотя бы примерно знает, как всё работает, и в состоянии правильно реализовать в нём какую-то проверку безопасности.

По сути, единственное, что делает планировщик, — это пытается запустить задачу в определённое время и прислать результат на электронную почту. Для простых и незначительных задач пользователей таких возможностей вполне достаточно.

Но для более важных системных задач стоит обернуть вокруг cron(8) и вызываемых им задач дополнительную инфраструктуру. Если вам хочется отслеживать выполняемые задачи, то существует несколько способов повысить надёжность работы с cron(8).

Применяйте принцип минимальной привилегии

Шестой столбец в системном файле crontab(5) — это имя пользователя, который должен запускать задачу:

0 * * * * root cron-task

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

0 * * * * myappcron cron-task

Это делается не только из соображений безопасности (хотя их тоже следует учитывать); данная мера защищает вас от таких неприятностей, как ошибки сценариев, которые пытаются удалить все системные директории.

Также старайтесь не запускать задачи с системами баз данных (как, например, MySQL) через пользователя root с правами администратора. Лучше сделайте это под другим пользователем…

Или даже создайте специального пользователя с ограниченными разрешениями и уникальным случайным паролем, который будет храниться в защищённом файле ~/.my.cnf. К примеру, для задачи резервного копирования MySQL требуется всего лишь несколько разрешений: SELECT, SHOW VIEW и LOCK TABLES.

Конечно же, иногда действительно нужно заходить под root. В особо конфиденциальных случаях можно даже воспользоваться sudo(8) с соответствующими опциями NOPASSWD, чтобы назначенный пользователь мог запускать только определённые задачи под root и ничего более.

Тестируйте задачи

Перед тем как добавить задачу в файл crontab(5), необходимо протестировать её в командной строке в роли пользователя, который будет запускать задачу, и с теми же параметрами среды. Если вы будете запускать задачу как root, то воспользуйтесь чем-то вроде su или sudo -i , чтобы сначала получить root-оболочку с ожидаемой средой пользователя:

$ sudo -i -u cronuser $ cron-task

Как только задача «отработала» в командной строке, добавьте её в файл crontab(5). Измените настройки времени так, чтобы задача запустилась через несколько минут, а затем просмотрите /var/log/syslog с помощью команды tail -f и убедитесь, что задача запускается без ошибок и выполняется правильно:

May 7 13:30:01 yourhost CRON[20249]: (you) CMD (cron-task)

Поначалу такая процедура кажется педантичной, но очень скоро становится привычной и избавляет от множества хлопот, ведь так просто предположить что-то, что есть в вашей среде, но отсутствует в среде использования cron(8).

А ещё это необходимая проверка того, что ваш файл crontab(5) имеет правильную структуру — некоторые реализации cron(8) не загружают целый файл, если одна из строк имеет неправильный формат.

При необходимости в начале файла вы можете задать произвольные переменные среды для задач:

MYVAR=myvalue 0 * * * * you cron-task

Не отказывайтесь от вывода ошибок или полезных результатов выполнения

Скорее всего, вы уже встречали руководства в сети, в которых для того чтобы crontab(5) не рассылал стандартные результаты и/или типовые письма с ошибками каждые 5 минут, в конце описания задания добавляются операторы перенаправления оболочки. Этот кустарный способ очень популярен для запуска задач по веб-разработке путём автоматизации запроса к URL через curl(1) или wget(1):

*/5 * * * root curl https://example.com/cron.php >/dev/null 2>&1

Полное игнорирование результатов выполнения — это всегда плохо. Ведь если вам выдают только нужные результаты или ошибки и у вас нет других задач или средств мониторинга выполнения заданий, то вы не заметите проблем (и не узнаете, в чём они заключаются).

В случае с curl(1) столько всего могло пойти не так, а вы заметили бы это слишком поздно:

  • Скрипт мог сломаться и вернуть ошибку 500.
  • URL задачи cron.php мог измениться, а кто-то забыл добавить перенаправление HTTP 301.
  • Но даже с настроенным редиректом HTTP 301 вы не сможете на него перейти, если не воспользуетесь в curl(1) командами -L или --location.
  • Клиент мог попасть в чёрный список, на запросе мог сработать брандмауэр… его могли заблокировать автоматические или ручные процессы, которые ошибочно пометили запрос как спам.
  • При несоответствии шифра или протокола в HTTPS могло сломаться подключение.

Автор встречал всё из вышеперечисленного, и даже очень часто.

Лучше потратить какое-то время на чтение справочной страницы вызываемой задачи и поискать, как правильно управлять результатами выполнения, чтобы получать действительно нужные вам данные. Например, в случае с curl(1) я заметил, что хорошо работает следующая формула:

curl -fLsS -o /dev/null http://example.com/
  • -f: если код ответа HTTP — это ошибка, то сгенерировать сообщение об ошибке, а не страницу 404.
  • -L: если указано перенаправление HTTP 301, то попробовать перейти на него.
  • -sS: не показывать индикатор выполнения (-S также не позволяет -s блокировать сообщения об ошибках).
  • -o /dev/null: отправить стандартный результат выполнения (фактически возвращённую страницу) в /dev/null.

Таким образом, в соответствии со старой Unix-философией Правила тишины ваш запрос curl(1) будет молчать, пока всё работает как надо.

Вы можете не согласиться с некоторыми из перечисленных вариантов; можете посчитать, что, например, нужно сохранять полный вывод возвращённой страницы или выдавать ошибку, а не тихо переходить на редирект 301, или же вообще предпочтёте пользоваться wget(1).

Суть в том, что вы пробуете разобраться, чего и при каких обстоятельствах ждать от вызываемой программы, а вместо бездумного удаления всех результатов и (что ещё хуже) ошибок пытаетесь как можно лучше подстроить программу под ваши требования. Поработайте с законом Мерфи; исходите из того, что всё, что могло пойти не так, со временем пойдёт не так.

Отправляйте результат выполнения в полезное место

Ещё одна распространённая ошибка — не прописывать вверху файла crontab(5) правильный MAILTO , куда будут отправляться все ошибки и результаты выполнения задач.

Для отправки своих сообщений cron(8) использует реализацию системной почты, а стандартные конфигурации для почтовых агентов чаще всего отправляют сообщение в файл mbox в /var/mail/$USER, который могут никогда и не читать, что сводит на нет всю концепцию рассылки результатов и ошибок.

Но это легко исправить. Сделайте так, чтобы сообщения отправлялись на адрес, который вы действительно проверяете с сервера… возможно, даже с помощью mail(1):

$ printf '%s\n' 'Test message' | mail -s 'Test subject' you@example.com

Как только вы проверили корректную настройку почтового агента и убедились, что на почтовый ящик доставляются письма, пропишите этот адрес в переменной MAILTO в начале файла:

MAILTO=you@example.com 0 * * * * you cron-task-1 */5 * * * * you cron-task-2

Если же вы не хотите получать результаты выполнения задачи на электронную почту, то имеется и другой способ. С помощью такого инструмента, как logger(1), вы можете отправлять эти данные в syslog:

0 * * * * you cron-task | logger -it cron-task

Ещё можно настроить псевдонимы в системе, чтобы перенаправлять ваши системные письма на тот адрес, которым пользуетесь. Для постфикса воспользуйтесь файлом aliases(5).

Иногда я пользуюсь этим способом, если задача может завершиться несколькими строками выходных значений, которые будут полезны для последующего анализа, но обычные результаты stderr отправляю через MAILTO. Если вы не хотите пользоваться syslog (возможно, из-за большого объёма и/или частоты отправляемых данных), то всегда можно настроить файл журнала /var/log/cron-task.log… но не забудьте добавить для этого правило logrotate(8)!

Добавляйте задачи в собственный файл сценария оболочки

В идеале команды в определениях crontab(5) должны состоять из нескольких слов, а сам файл содержать 1–2 команды. Если команда выполняется за экраном, то, скорее всего, она слишком длинная для crontab(5), поэтому вам следует добавить её в собственный сценарий. Эта идея особенно хороша, если для своих команд вы хотите эффективно пользоваться возможностями bash или других оболочек (помимо POSIX/Bourne /bin/sh)… или даже языком сценариев (например, Awk или Perl). Для разбора команд cron(8) по умолчанию использует системную реализацию /bin/sh.

Файлы crontab(5) не допускают многострочных команд и имеют ряд других недостатков (например, знаки процента (%) нужно экранировать обратной косой чертой). Поэтому хранить как можно больше конфигураций вне crontab(5) — это, в общем-то, и неплохая идея.

Если вы запускаете задачи cron(8) от имени несистемного пользователя и не можете добавить сценарии в системный bindir в виде /usr/local/bin, то правильнее всего будет прописать свой собственный скрипт и добавить ссылку на него в PATH. Я предпочитаю ~/.local/bin, но встречал ссылки и на ~/bin. Сохраните сценарий в ~/.local/bin/cron-task, сделайте его исполняемым с помощью chmod +x и включите эту директорию в определение среды PATH в верхушке файла:

PATH=/home/you/.local/bin:/usr/local/bin:/usr/bin:/bin MAILTO=you@example.com 0 * * * * you cron-task

Собственная директория с пользовательскими сценариями под личные нужды имеет массу преимуществ, но это тема для другой статьи.

Избегайте /etc/crontab

Если ваша реализация cron(8) это поддерживает, то вместо бесконечно длинного файла /etc/crontab попробуйте вынести задачи в отдельный файл /etc/cron.d:

$ ls /etc/cron.d system-a system-b raid-maint

Такая структура позволит логически сгруппировать файлы конфигураций так, что вы (и другие администраторы) сможете быстрее находить нужные задачи. Кроме того, вы сможете сделать какие-то файлы доступными для редактирования только определённым пользователям, чтобы снизить вероятность конфликтов изменений. Здесь, кстати, пригодится и sudoedit(8).

Ещё один плюс в том, что он лучше работает с контролем версий. Так что, если собирается изрядное количество таких файлов задач либо они обновляются чаще раза за пару месяцев, то я запускаю Git-репозиторий для их отслеживания:

$ cd /etc/cron.d $ sudo git init $ sudo git add --all $ sudo git commit -m "First commit"

Если вы редактируете файл crontab(5) для задач только определённого пользователя, то воспользуйтесь инструментом crontab(1). Для изменения crontab(5) напечатайте crontab -e. Так ваш $EDITOR сможет внести изменения во временный файл, который будет установлен при выходе. Файлы сохранятся в специально выделенной директории, в моей системе она называется /var/spool/cron/crontabs.

В системах, которые я поддерживал, готовый шаблон /etc/crontab мог никогда не меняться. Это нормально.

Добавьте время ожидания

Обычно cron(8) разрешает задаче выполняться бесконечно, так что если вам этого не нужно, то следует прописать время ожидания (тайм-аут) в опциях вызываемой программы либо включить его в сценарий. Если в самой команде нужных параметров нет, то одним из возможных способов реализации станет обёртка команды timeout(1) в coreutils:

0 * * * * you timeout 10s cron-task

В Википедии Грега (Greg’s Wiki) можно найти целый ряд дополнительных предложений по реализации тайм-аутов.

Избегайте переполнения — включите блокировку файла

cron(8) запускает новый процесс вне зависимости от того, завершились предыдущие запуски или нет. Так что если вы хотите избежать блокировки задач с длительным временем выполнения, то в GNU/Linux можно воспользоваться обёрткой flock(1) для системного вызова flock(2) — она настроит особый файл блокировки, который предотвращает параллельное выполнение задач в более чем одном экземпляре cron.

0 * * * * you flock -nx /var/lock/cron-task cron-task

В Википедии Грега (Greg’s Wiki) можно найти подробное обсуждение типовой блокировки файла для сценариев, включая важные нюансы о «развёртывании собственных файлов», если flock(1) недоступен.

Если вам важно запускать какие-то действия в определённом порядке, то подумайте, нужно ли разводить их в отдельные задачи? Возможно, если собрать задачи в один сценарий оболочки, вам будет проще организовать их последовательное выполнение.

Используйте статусы выхода с пользой

Если ваша задача в cron(8) (или команды внутри её сценария) завершается ненулевыми значениями, то лучше запустить команды, которые смогли бы правильно обработать ошибки. Например, очистить соответствующие ресурсы и отправить информацию о текущем статусе задания в средства мониторинга. Если вы пользуетесь Nagios Core или его вариациями, то присмотритесь к send_nsca — он может передавать пассивную проверку статуса задачи на сервер мониторинга. Я написал простой сценарий nscaw, который делает это за меня:

0 * * * * you nscaw CRON_TASK -- cron-task

Рассмотрите альтернативы cron(8)

Если ваша машина работает не круглые сутки, а задачу не нужно запускать в опредёленное время (допустим, она запускается раз в день или раз в неделю), то лучше установите anacron и перекиньте сценарии в /etc соответствующих директорий cron.hourly, cron.daily, cron.monthly и cron.weekly. Обратите внимание, что в /etc/crontab по умолчанию для Debian и Ubuntu GNU/Linux есть хуки для запуска, но задачи запускаются, только если не установлен anacron(8).

Если вы используете cron(8), чтобы «спросить» директорию об изменениях и запустить сценарий только при наличии каких-то изменений, то в GNU/Linux лучше прописать демона на основе inotifywait(1).

И, наконец, если вам нужен больший контроль над тем, когда и как запускаются задачи, а возможности cron(8) в этом плане вас не устраивают, то, возможно, стоит написать демона, который будет последовательно работать на сервере и разветвлять процессы для своей задачи.

Например, это позволит запускать задачу чаще одного раза в минуту. Не зацикливайтесь на cron(8) как на единственном варианте для асинхронного управления задачами!

А мы поможем вам прокачать навыки или освоить профессию в IT, актуальную в любое время.

  • Профессия Fullstack-разработчик на Python
  • Профессия Data Scientist

Краткий каталог курсов и профессий

Data Science и Machine Learning

  • Профессия Data Scientist
  • Профессия Data Analyst
  • Курс «Математика для Data Science»
  • Курс «Математика и Machine Learning для Data Science»
  • Курс по Data Engineering
  • Курс «Machine Learning и Deep Learning»
  • Курс по Machine Learning

Python, веб-разработка

  • Профессия Fullstack-разработчик на Python
  • Курс «Python для веб-разработки»
  • Профессия Frontend-разработчик
  • Профессия Веб-разработчик

Мобильная разработка

  • Профессия iOS-разработчик
  • Профессия Android-разработчик

Java и C#

  • Профессия Java-разработчик
  • Профессия QA-инженер на JAVA
  • Профессия C#-разработчик
  • Профессия Разработчик игр на Unity

От основ — в глубину

  • Курс «Алгоритмы и структуры данных»
  • Профессия C++ разработчик
  • Профессия Этичный хакер

А также

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *