Статьи

Полное руководство по использованию Cronjobs

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

Cron — это планировщик заданий на основе времени в Unix-подобных операционных системах, который запускает определенные задачи в будущем. Название происходит от греческого слова χρόνος (хронос), что означает время.

Наиболее часто используемая версия Cron известна как Vixie Cron, первоначально разработанная Полом Vixie в 1987 году.

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

Изображение Chronos

терминология

  • Работа: единица работы, ряд шагов, чтобы сделать что-то. Например, отправка электронного письма группе пользователей. В этой статье мы будем использовать задачу , задание , задание cron или событие взаимозаменяемо.

  • Демон: (/ ˈdiːmən / или / ˈdeɪmən /) — это компьютерная программа, которая работает в фоновом режиме и служит различным целям. Демоны часто запускаются во время загрузки. Веб-сервер — это демон, обслуживающий HTTP-запросы. Cron — это демон для запуска запланированных задач.

  • Задание Cron: задание Cron является запланированным заданием , которое запускается Cron в установленный срок.

  • Webcron: планировщик заданий на основе времени, который работает в среде веб-сервера. Он используется в качестве альтернативы стандартному Cron, часто на общих веб-хостах, которые не предоставляют доступ к оболочке.

Начиная

В этом руководстве предполагается, что вы используете операционную систему на основе Unix, например Ubuntu. Если нет, мы рекомендуем установить Homestead Improved — это 5-минутный процесс, который сэкономит вам годы.

Если мы заглянем в каталог /etc , мы увидим такие cron.hourly , как cron.hourly , cron.daily , cron.weekly и cron.monthly , каждый из которых соответствует определенной частоте выполнения. Один из способов планирования наших задач — поместить наши скрипты в соответствующий каталог. Например, чтобы запускать db_backup.php ежедневно, мы помещаем его в cron.daily . Если папка для заданной частоты отсутствует, нам сначала нужно ее создать.

Примечание. Этот подход использует скрипт run-parts , команду, которая запускает каждый исполняемый файл, который он находит в указанном каталоге.

Это самый простой способ запланировать задачу. Однако, если нам нужна большая гибкость, мы должны использовать Crontab.

Файлы Crontab

Cron использует специальные файлы конфигурации, называемые файлами crontab , которые содержат список заданий, которые необходимо выполнить. Crontab расшифровывается как Cron Table . Каждая строка в файле crontab называется заданием cron, которое напоминает набор столбцов, разделенных пробелом. В каждой строке указывается, когда и как часто должна выполняться определенная команда или сценарий.

В файле crontab пустые строки или строки, начинающиеся с # , пробелов или табуляции, будут игнорироваться. Строки, начинающиеся с # , считаются комментариями.

Активные строки в crontab являются либо объявлением переменной среды, либо заданием cron, и комментарии к активным строкам не допускаются.

Ниже приведен пример файла crontab только с одной записью:

 0 0 * * * / var / www / sites / db_backup . sh 

Первая часть 0 0 * * * — это выражение cron, которое указывает частоту выполнения. Вышеупомянутая работа cron будет выполняться один раз в день.

Пользователи могут иметь свои собственные файлы crontab, названные в честь их имени пользователя, зарегистрированного в /etc/passwd . Все пользовательские файлы crontab находятся в области спула Cron. Эти файлы не должны редактироваться напрямую. Вместо этого мы должны отредактировать их с помощью утилиты командной строки crontab .

Примечание. Каталог спулинга варьируется в разных дистрибутивах Linux. В Ubuntu это /var/spool/cron/crontabs то время как в CentOS это /var/spool/cron .

Чтобы отредактировать наш собственный файл crontab:

 crontab - e 

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

 export VISUAL = nano ; crontab - e 

После сохранения файла и выхода из редактора crontab будет проверен на точность. Если все настроено правильно, файл будет сохранен в каталог спула.

Примечание. Каждая команда в файле crontab выполняется с точки зрения пользователя, которому принадлежит crontab, поэтому, если ваша команда запускается от имени пользователя root (sudo), вы не сможете определить этот crontab из своей собственной учетной записи пользователя, если вы не войдете в систему как корень.

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

 crontab - l 

Мы также можем записать наши задания cron в файл и отправить его содержимое в файл crontab следующим образом:

 crontab / path / to / the / file / containing / cronjobs . txt 

Предыдущая команда перезапишет существующий файл crontab с помощью /path/to/the/file/containing/cronjobs.txt .

Чтобы удалить crontab, мы используем опцию -r :

 crontab - r 

Анатомия входа в Crontab

Анатомия записи в пользовательском уровне в crontab выглядит следующим образом:

 # ┌───────────── min (0 - 59) # │ ┌────────────── hour (0 - 23) # │ │ ┌─────────────── day of month (1 - 31) # │ │ │ ┌──────────────── month (1 - 12) # │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to Saturday, or use names; 7 is Sunday, the same as 0) # │ │ │ │ │ # │ │ │ │ │ # * * * * * command to execute 

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

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

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

 0 0 5-20/5 Feb 2 /path/to/command 

Предыдущее задание cron будет выполняться один раз в день каждые пять дней, с 5 по 20 февраля плюс все вторники февраля.

Важное замечание : Если и день месяца, и день недели имеют определенные значения (не звездочка), это создаст условие OR , означающее, что оба дня будут совпадать.

Синтаксис системных crontabs ( /etc/crontab ) немного отличается от пользовательских crontabs. Разница в том, что шестое поле — это не команда, а пользователь, от которого мы хотим запустить задание.

 * * * * * testuser / path / to / command 

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

Редактирование Crontab других пользователей

Возможно, нам придется редактировать файлы crontab других пользователей. Для этого мы используем опцию -u как -u ниже:

 crontab - u username - e 

Примечание. Мы можем редактировать файлы crontab других пользователей только как пользователь root или как пользователь с правами администратора.

Некоторые задачи требуют привилегий супер-администратора, поэтому их следует добавить в файл crontab пользователя root :

 sudo crontab -e 

Примечание: обратите внимание, что использование sudo с crontab -e отредактирует файл crontab пользователя root. Если нам нужно отредактировать crontab другого пользователя при использовании sudo , мы должны использовать опцию -u чтобы указать владельца crontab.

Чтобы узнать больше о команде crontab :

 man crontab 

Стандартные и нестандартные значения

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

Изменяется

Мы можем передать в диапазонах чисел:

 0 6-18 1-15 * * /path/to/command 

Вышеуказанное задание будет выполняться с 6:00 до 18:00 с 1 по 15 числа каждого месяца в году. Обратите внимание, что указанный диапазон является включающим, поэтому 1-5 означает 1,2,3,4,5.

Списки

Список — это группа значений, разделенных запятыми. Мы можем иметь списки в качестве значений полей:

 0 1,4,5,7 * * * /path/to/command 

Приведенный выше синтаксис запускает задание cron каждый день в 1, 4, 5 и 7 часов утра.

меры

Шаги можно использовать с диапазонами или звездочкой (*) . Когда они используются с диапазонами, они указывают количество значений, пропускаемых до конца диапазона. Они определяются символом / после диапазона, за которым следует число. Рассмотрим следующий синтаксис:

 0 6 - 18 / 2 * * * / path / to / command 

Вышеуказанное задание cron будет выполняться каждые два часа с 6 до 18 часов.

Когда шаги используются со звездочкой, они просто указывают частоту этого конкретного поля. Например, если мы устанавливаем минуты на */5 , это просто означает каждые пять минут .

Мы можем комбинировать списки, диапазоны и шаги вместе для более гибкого планирования событий:

 0 0 - 10 / 5 , 14 , 15 , 18 - 23 / 3 1 1 * / path / to / command 

Вышеуказанное мероприятие будет проходить каждые пять часов с полуночи 1 января до 10:00, 14:00, 15:00, а также каждые три часа с 18:00 до 23:00.

имена

Для полей месяц и день недели мы можем использовать первые три буквы определенного дня или месяца, такие как Sat , sun , Feb , Sep и т. Д.

 * * * Feb,mar sat,sun /path/to/command 

Предыдущая работа cron будет выполняться только по субботам и воскресеньям февраля и марта.

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

Предопределенные определения

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

  • @yearly, @annually Запускать раз в год в полночь 1 января (0 0 1 1 *)
  • @monthly Запускать раз в месяц, в полночь первого дня месяца (0 0 1 * *)
  • @ еженедельно бегать раз в неделю в полночь воскресенья (0 0 * * 0)
  • @daily Запускать раз в день в полночь (0 0 * * *)
  • @hourly Run в начале каждого часа (0 * * * *)
  • @reboot Запустить один раз при запуске

Несколько команд в одном задании Cron

Мы можем запустить несколько команд в одном задании cron, разделив их точкой с запятой ( ; ).

 * * * * * / path / to / command - 1 ; / path / to / command - 2 

Если текущие команды зависят друг от друга, мы можем использовать двойной амперсанд (&&) между ними. В результате вторая команда не будет выполнена, если первая не выполнится.

 * * * * * / path / to / command - 1 && / path / to / command - 2 

Переменные среды

Переменные окружения в файлах crontab имеют вид VARIABLE_NAME = VALUE (пробелы вокруг знака равенства необязательны). Cron не получает никаких файлов запуска из домашнего каталога пользователя (когда он запускает cron уровня пользователя). Это означает, что мы должны вручную установить любые пользовательские настройки, необходимые для наших задач.

Cron daemon автоматически устанавливает некоторые переменные окружения при запуске. HOME и LOGNAME устанавливаются из информации о владельце crontab в /etc/passwd . Однако мы можем переопределить эти значения в нашем файле crontab, если в этом есть необходимость.

Есть также еще несколько переменных, таких как SHELL , определяющих оболочку, которая запускает команды. По умолчанию это /bin/sh . Мы также можем установить PATH для поиска программ.

 PATH = / usr / bin ; / usr / local / bin 

Важно : мы должны заключить значение в кавычки, если в значении есть пробел. Обратите внимание, что значения считаются обычными строками и никоим образом не интерпретируются и не анализируются.

Разные часовые пояса

Cron использует настройку часового пояса системы при оценке записей в crontab. Это может вызвать проблемы для многопользовательских систем с пользователями в разных часовых поясах. Чтобы обойти эту проблему, мы можем добавить переменную окружения с именем CRON_TZ в наш файл crontab. В результате все записи в crontab будут проанализированы на основе указанного часового пояса.

Как Cron интерпретирует файлы Crontab

После запуска Cron выполняет поиск в области спула, чтобы найти и загрузить файлы crontab в память. Кроме того, он проверяет каталоги /etc/crontab и /etc/cron.d наличие системных crontabs.

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

В дополнение к этому, Cron регулярно (каждую минуту) проверяет, modtime время модификации каталога modtime (время модификации). Если это так, он проверяет modetime всех загруженных crontabs и перезагружает те, которые изменились. Вот почему нам не нужно перезапускать демон при установке нового задания cron.

Cron Permissions

Мы можем указать, какой пользователь должен использовать Cron, а какой нет. Есть два файла, которые играют важную роль, когда речь идет о разрешениях cron: /etc/cron.allow и /etc/cron.deny .

Если существует /etc/cron.allow , то для использования crontab в этом файле должно быть указано наше имя пользователя. Если /etc/cron.deny существует, он не должен содержать нашего имени пользователя. Если ни один из этих файлов не существует, то в зависимости от параметров конфигурации, зависящих от сайта, суперпользователь или все пользователи смогут использовать команду crontab . Например, в Ubuntu, если ни один файл не существует, все пользователи могут использовать crontab по умолчанию.

Мы можем поместить ALL в файл /etc/cron.deny чтобы запретить всем пользователям использовать cron:

 echo ALL > / etc / cron . deny 

Примечание : если мы создаем файл /etc/cron.allow , нет необходимости создавать файл /etc/cron.deny как он имеет тот же эффект, что и файл /etc/cron.deny со ALL в нем.

Перенаправление вывода

Мы можем перенаправить вывод нашего задания cron в файл, если команда (или скрипт) имеет какой-либо вывод:

 * * * * * / path / to / php / path / to / the / command > > / var / log / cron . log 

Мы можем перенаправить стандартный вывод в dev null, чтобы не получать электронную почту (подробнее об этом см. Ниже), но при этом разрешаем отправку стандартной ошибки в виде электронной почты:

 * * * * * / path / to / php / path / to / the / command > / dev / null 

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

 * * * * * / path / to / php / path / to / the / command > / dev / null 2 > & 1 

Это означает «отправить как стандартный вывод, так и вывод ошибок в забвение».

Отправить результат по электронной почте

Вывод отправляется по почте владельцу crontab или электронной почты, указанных в MAILTO среды MAILTO (если стандартный вывод или стандартная ошибка не перенаправляются, как указано выше).

Если MAILTO установлено пустым, электронное письмо не будет отправлено в результате выполнения задания cron.

Мы можем установить несколько писем, разделяя их запятыми:

 MAILTO=admin@example.com,dev@example.com * * * * * /path/to/command 

Cron и PHP

Мы обычно запускаем наши сценарии командной строки PHP, используя исполняемый файл PHP.

 php script . php 

В качестве альтернативы, мы можем использовать shebang в начале скрипта и указать на исполняемый файл PHP:

 #! /usr/bin/php <?php // PHP code here 

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

Чтобы иметь более надежные сценарии командной строки PHP, мы можем использовать сторонние компоненты для создания консольных приложений, таких как Symfony Console Component или Laravel Artisan . Эта статья является хорошим началом использования консольного компонента Symfony.
Создание консольных команд с использованием Laravel Artisan также было рассмотрено здесь . Если вы предпочитаете использовать другой инструмент командной строки для PHP, у нас есть сравнение здесь .

Задачи перекрываются

Есть моменты, когда запланированные задачи занимают намного больше времени, чем ожидалось. Это приведет к дублированию, то есть некоторые задачи могут выполняться одновременно. Это может не вызывать проблемы в некоторых случаях, но когда они изменяют одни и те же данные в базе данных, у нас будет проблема. Мы можем преодолеть это, увеличив частоту выполнения задач, но все же не гарантируется, что эти совпадения больше не повторятся.

У нас есть несколько вариантов предотвращения наложения заданий cron.

Использование Flock

Flock — хороший инструмент для управления файлами блокировки из сценариев оболочки или командной строки. Эти файлы блокировки полезны для того, чтобы узнать, запущен ли скрипт.

При использовании вместе с Cron соответствующие задания cron не запускаются, если существует файл блокировки. Вы можете установить Flock, используя apt-get или yum зависимости от дистрибутива Linux.

 apt-get install flock 

Или

 yum install flock 

Рассмотрим следующую запись в crontab:

 * * * * * / usr / bin / flock -- timeout = 1 / path / to / cron . lock / usr / bin / php / path / to / scripts . php 

В предыдущем примере flock ищет /path/to/cron.lock . Если блокировка получена за одну секунду, он запустит скрипт, в противном случае произойдет сбой с кодом выхода 1.

Использование механизма блокировки в скриптах

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

 <?php $lockfile = sys_get_temp_dir ( ) . '/' md5 ( __FILE__ ) . '.lock' ; $pid = file_exists ( $lockfile ) ? trim ( file_get_contents ( $lockfile ) ) : null ; if ( is_null ( $pid ) || posix_getsid ( $pid ) === false ) {  // Do something here  // And then create/update the lock file file_put_contents ( $lockfile , getmypid ( ) ) ; } else { exit ( 'Another instance of the script is already running.' ) ; } 

В предыдущем коде мы храним pid текущего процесса PHP в файле, который находится во temp каталоге системы. Каждый PHP-скрипт имеет свой собственный файл блокировки, который является MD5-хэшем имени файла скрипта.

Сначала мы проверяем, существует ли файл блокировки, а затем получаем его содержимое, которое является идентификатором процесса последнего запущенного экземпляра сценария. Затем мы передаем pid PHP-функции posix_getsid , которая возвращает идентификатор сеанса процесса. Если posix_getsid возвращает false это означает, что процесс больше не выполняется, и мы можем безопасно запустить новый экземпляр.

Anacron

Одна из проблем Cron заключается в том, что она предполагает непрерывную работу системы (24 часа в сутки). Это создает проблемы для машин, которые не работают весь день (например, персональные компьютеры). Если система отключится во время запланированного запуска задачи, Cron не запустит эту задачу задним числом.

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

Только root или пользователь с правами администратора могут управлять задачами Anacron. Anacron не работает в фоновом режиме, как демон, а только один раз, выполняя задачи, которые должны быть выполнены.

Anacron использует файл конфигурации (как и crontab) с именем anacrontabs . Этот файл находится в каталоге /etc

Содержимое этого файла выглядит так:

 # /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL = / bin / sh PATH = / sbin : / bin : / usr / sbin : / usr / bin MAILTO = root # the maximal random delay added to the base delay of the jobs RANDOM_DELAY = 45 # the jobs will be started during the following hours only START_HOURS_RANGE = 3 - 22 #period in days delay in minutes job-identifier command 1 5 cron . daily nice run - parts / etc / cron . daily 7 25 cron . weekly nice run - parts / etc / cron . weekly @monthly 45 cron . monthly nice run - parts / etc / cron . monthly 

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

Третий столбец — это уникальное имя, которое используется для идентификации задачи в файлах журнала Anacron.

Четвертый столбец — фактическая команда для запуска.

Рассмотрим следующую запись:

 1 5 cron . daily nice run - parts / etc / cron . daily 

Вышеуказанные задачи выполняются ежедневно, через 5 минут после запуска Anacron. Он использует run-parts для выполнения всех скриптов в /etc/cron.daily .

Вторая запись в приведенном выше списке выполняется каждые 7 дней (еженедельно) с 25-минутной задержкой.

Столкновение Крона и Анакрона

Как вы, наверное, заметили, Cron также настроен на выполнение скриптов внутри каталогов /etc/cron.* . Такое возможное столкновение с Anacron обрабатывается по-разному в разных версиях Linux. В Ubuntu Cron проверяет, присутствует ли Anacron в системе, и если это так, он не будет выполнять сценарии в каталогах /etc/cron.* .

В других версиях Linux Cron обновляет временные метки Anacron при запуске задач, поэтому Anacron не выполнит их, если они уже были запущены Cron.

Быстрое устранение неполадок

Абсолютный Путь к командам

Хорошей привычкой является использование абсолютных путей ко всем исполняемым файлам, которые мы используем в файле crontab.

 * * * * * /usr/local/bin/php /absolute/path/to/the/command 

Убедитесь, что Cron Daemon запущен

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

 ps aux | grep crond 

Вывод должен быть похож на это:

 root 7481 0.0 0.0 116860 1180 ? Ss 2015 0 : 49 crond 

Проверьте файлы /etc/cron.allow и /etc/cron.deny

Если задания cron не запущены, нам нужно проверить, существует ли /etc/cron.allow . Если это так, мы должны убедиться, что наше имя пользователя указано в этом файле. Если /etc/cron.deny существует, мы должны убедиться, что наше имя пользователя не указано в этом файле.

Если мы отредактируем файл crontab пользователя, тогда как пользователь не существует в файле /etc/cron.allow , в том числе пользователь в /etc/cron.allow не запустит cron, пока мы не отредактируем файл crontab.

Выполнить разрешение

Нам нужно убедиться, что владелец crontab имеет разрешения на выполнение всех команд и сценариев в файле crontab. В противном случае cron не будет работать. Разрешения на выполнение могут быть добавлены в любую папку или файл с помощью chmod +x /some/file.php

Новая строка символов

Каждая запись в crontab должна заканчиваться новой строкой. Это означает, что после последней записи crontab должна быть пустая строка, иначе последнее задание cron никогда не запустится.

Завершение

Cron — это демон, управляющий списком событий, запланированных на будущее. Эти задания перечислены в специальных конфигурационных файлах, называемых файлами crontab. Пользователи могут иметь свой собственный файл crontab, если им разрешено использовать Cron, на основе /etc/cron.deny files /etc/cron.allow или /etc/cron.deny files . В дополнение к пользовательским заданиям cron, Cron также загружает общесистемные задания cron, которые немного различаются по синтаксису.

Нашими задачами обычно являются PHP-скрипты или утилиты командной строки. В системах, которые не работают постоянно, мы можем использовать Anacron для запуска событий, которые происходят в течение n дней.
При работе с Cron мы также должны помнить о задачах, перекрывающих друг друга, чтобы предотвратить потерю данных. После завершения задания cron выходные данные будут отправлены владельцу crontab и / или электронным MAILTO указанным в переменной среды MAILTO .

Вы узнали что-нибудь новое из этого поста? Мы что-то пропустили? Или вам просто понравился этот пост и вы хотите рассказать нам, насколько он был исчерпывающим? Дайте нам знать в комментариях ниже!