Содержание
Cron Job сделал планирование различных задач очень простым, но отладка этих скриптов из Cron Job не менее сложна. Это связано с тем, что Cron Job выполняет команды, которые вы ему предоставляете, всегда в одно определенное время; это означает, что у вас есть только два способа запустить Cron Job:
- Ждать, пока Cron Job запустится в указанное вами время, которое может составлять секунды, минуты или даже часы.
- Запускать задание Cron каждую минуту и смотреть, не выдает ли оно какую-нибудь ошибку (большинство людей поступают именно так)
А что, если я скажу вам, что есть и третий способ: запускать задание Cron вручную.
Этот подход поможет нам запустить любой из наших скриптов немедленно, не дожидаясь, пока Crontab выполнит наше задание в определенное время. Кроме того, при запуске задания будет воспроизведена та же среда, которую использует Cron при выполнении своих заданий. Очень полезно для отладки любых проблем, связанных с Cron, если вы спросите меня.
Шаги
Давайте разберемся с тем, как запустить задание Cron вручную.
Шаг 1: Получите PATH, которые использует ваше обычное задание Cron
Самая большая разница в запуске скрипта непосредственно из командной строки и из задания Cron - это разница в значениях PATH.
Очень часто Cron Job не выполняется из-за того, что в PATH не указаны исполняемые файлы, например, для Ruby, PERL и т.д., и из-за того, что эти исполняемые файлы не найдены, скрипт, который работал правильно в разработке или даже из командной строки на рабочем сервере, больше не будет работать при запуске того же скрипта из Cron Job.
Выполните команду crontab -e для редактирования вашего crontab и добавьте следующую запись в начало (или в любое другое место файла):
* * * * * * /usr/bin/env > /home/deploy/cron-env.
Обратите внимание, что /home/deploy - это корневой путь моего зарегистрированного пользователя на производственном сервере, у вас он может быть другим.
С помощью приведенной выше записи в crontab мы указываем заданию Cron запускаться каждую минуту и добавлять PATH, которые оно получает от команды ”/usr/bin/env”, в файл с именем “cron-env”.
Подождите минуту и проверьте содержимое файла “cron-env” с помощью команды cat cron-env, оно должно быть примерно таким:
HOME=/home/deploy
LOGNAME=deploy
PATH=/usr/bin:/bin
LANG=en_US.UTF-8
SHELL=/bin/sh
PWD=/home/deploy
Обратите внимание, что “deploy” - это имя вошедшего в систему пользователя.
Вам следует удалить задание Cron, которое мы добавили ранее, из Crontab, поскольку оно отслужило свой срок, предоставив нам PATH, которые понадобятся для запуска команд в качестве задания Cron.
Шаг 2: Создайте bash-скрипт для запуска любой команды, похожей на Cron Job
Создайте новый файл командой nano run-as-cron и добавьте в него следующее:
#!/bin/bash /usr/bin/env -i $(cat /home/deploy/cron-env) "$@" .
Вот что делает приведенная выше команда:
/usr/bin/env- это путь к команде env, которая используется для поиска и выполнения указанной команды с измененным окружением.- Опция
-iуказывает env начать с пустого окружения, игнорируя унаследованные переменные окружения. $(cat /home/deploy/cron-env)использует команду “cat” для чтения содержимого файла, расположенного по адресу /home/deploy/cron-env, а затем использует подстановку команд$(...)для включения содержимого файла в качестве аргументов в команду env. Ожидается, что содержимое файла будет являться назначением переменной окружения для любой команды, запущенной с помощью этого bash-скрипта."$@"- это специальная переменная, которая представляет все аргументы, передаваемые скрипту или команде. В данном контексте она позволяет скрипту или команде, выполняемой с помощью env, получить те же аргументы, которые были переданы исходному скрипту или команде, содержащей эту строку.
Например, если вы запустили команду ./run-as-cron /path/to/script -with arguments, то все, что находится после ”./run-as-cron”, будет передано как здесь и выполнено этим скриптом.
Шаг 3: Запустите любую команду, копируя поведение Cron
Теперь мы готовы запустить любую команду, используя те же переменные окружения, которые использует задание Cron во время выполнения.
Теперь вы можете запустить нужную вам команду с помощью:
./run-as-cron /path/to/script --with arguments --and parameters
Например, если у вас есть скрипт, скажем, для чтения CSV-файла и разбора его в JSON, вы можете запустить эту команду прямо сейчас:
./run-as-cron /home/deploy/production/scripts/parse-csv-as-json '/home/deploy/production/csv-files/employees.csv'
Это предполагает, что вы принимаете путь к файлу в качестве аргумента внутри скрипта.
Вот и все, теперь вы можете запустить задание Cron вручную и сразу же отладить результат!
Если вы являетесь разработчиком Ruby on Rails, проследите за развитием событий, поскольку у меня есть для вас бонусный совет.
Бонус: Запуск задач Ruby on Rails, копирующих поведение Cron
Не имея отношения к этому руководству и будучи сам разработчиком Rails, я решил приложить бонусный пример по запуску задачи rake, выполняя ее как задание Cron вручную.
Я также предполагаю, что вы уже настроили гем whenever и добавили несколько задач Rake в “config/schedule.rb”.
Теперь, например, если у вас есть задача rake, которая отправляет вам письмо раз в день со списком пользователей, которые зарегистрировались вчера в вашем приложении, то команда может выглядеть следующим образом:
./run-as-cron /bin/bash -l -c 'cd /home/deploy/production/your-app/current && RAILS_ENV=production /home/deploy/.rbenv/shims/bundle exec rake users:registered_yesterday --silent >> log/whenever.log 2>&1'
Я только что скопировал команду, которая будет выполняться при развертывании Rails-приложения с помощью “Capistrano”, вот краткое объяснение команды bash и опций, использованных выше:
/bin/bashуказывает оболочку Bash, которая будет использоваться для выполнения команды.- Опция
-lзаставляет Bash действовать так, как если бы он был вызван как оболочка для входа в систему. Это означает, что он будет читать определенные конфигурационные файлы, специфичные для входа в систему. - Опция
-c '...'позволяет передать команду в виде строки для выполнения Bash. Команда, заключенная в одинарные кавычки, является собственно выполняемой командой. cd /home/deploy/production/your-app/current && RAILS_ENV=production /home/deploy/.rbenv/shims/bundle exec rake users:registered_yesterdayуказывает скрипту изменить рабочий каталог на папку ”…. /current” и выполнить задание Rake.>> log/whenever.log 2>&1добавляет стандартный вывод и стандартную ошибку в файл “log/whenever.log”. Это распространенная техника, позволяющая фиксировать в файле журнала как обычный вывод, так и ошибки.
Заключение
В этом коротком и понятном руководстве мы узнали, как можно запустить задание Cron вручную и сразу же приступить к отладке проблем, а не ждать несколько минут или часов, чтобы отладить проблему.
Надеюсь, вы также узнали о некоторых новых опциях и методах работы с командами bash, как и я во время написания этого блога. Наконец, я надеюсь, что это поможет вам сэкономить много времени в будущем при отладке любого задания Cron.
Спасибо за чтение. Счастливой работы!