Запуск cron каждые 30 секунд

197

Итак, у меня есть хрон, который мне нужно запускать каждые 30 секунд.

Вот что у меня есть:

*/30 * * * * /bin/bash -l -c 'cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'''

Он работает, но работает ли он каждые 30 минут или 30 секунд?

Кроме того, я читал, что Cron может быть не лучшим инструментом для использования, если я запускаю его так часто. Есть ли другой лучший инструмент, который я могу использовать или установить на Ubuntu 11.04, который будет лучшим вариантом? Есть ли способ исправить вышеуказанный cron?

  • 0
    CommaToast, а что произойдет, если ваше приложение Javascript или Java по какой-то причине перестанет работать и закроется? Как это перезапустится? :-)
  • 12
    Добавьте небольшое приложение NodeJS, смеется. Почему не маленькое приложение на C ++? Пока мы на этом, мы можем назвать его «cron» и запустить его как сервис.
Показать ещё 2 комментария
Теги:
cron
scheduled-tasks
crontab

16 ответов

522
Лучший ответ

У вас есть */30 в указателе минут - это означает каждую минуту, но с шагом в 30 (другими словами, каждые полчаса). Поскольку cron не переходит к субминутным разрешениям, вам нужно будет найти другой способ.

Одна возможность, хотя и немного клочья, состоит в том, чтобы иметь два задания, одно смещение на 30 секунд:

* * * * * /path/to/executable param1 param2
* * * * * ( sleep 30 ; /path/to/executable param1 param2 )

Оба задания cron запускаются каждую минуту, но последняя будет ждать полминуты перед выполнением "мяса" задания, /path/to/executable.

  • 11
    Это отличный обходной путь, так что я думаю, что он превосходит его заблуждение
  • 0
    это тоже не сработает? * * * * * ( /path/to/executable param1 param2; sleep 30 ; /path/to/executable param1 param2 )
Показать ещё 9 комментариев
54

Вы не можете. Cron имеет 60-секундную гранулярность.

* * * * * cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
* * * * * sleep 30 && cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''
  • 0
    Этот синтаксис эквивалентен синтаксису paxdiablo? Или есть тонкие различия?
  • 0
    Разница в том, что я использовал оригинальный путь к двоичному файлу. @paxdiablo использовал своего рода метасинтаксис. (и вызывает вложенную оболочку)
Показать ещё 2 комментария
36

Гранулярность Cron находится в минутах и ​​не предназначена для пробуждения каждые x секунд, чтобы что-то запускать. Запустите свою повторяющуюся задачу в цикле, и она будет делать то, что вам нужно:

#!/bin/env bash
while [ true ]; do
 sleep 30
 # do what you need to here
done
  • 48
    Имейте в виду, что это не совсем то же самое. Если задание занимает 25 секунд (например), оно будет запускаться каждые 55 секунд, а не каждые 30 секунд. Это может не иметь значения, но вы должны знать о возможных последствиях.
  • 7
    Вы можете запустить задание в фоновом режиме, тогда оно будет выполнено почти ровно через 30 секунд.
Показать ещё 6 комментариев
21

Нет необходимости в двух входах cron, вы можете поместить их в один:

* * * * * /bin/bash -l -c "/path/to/executable; sleep 30 ; /path/to/executable"

поэтому в вашем случае:

* * * * * /bin/bash -l -c "cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\'' ; sleep 30 ; cd /srv/last_song/releases/20120308133159 && script/rails runner -e production '\''Song.insert_latest'\''"

  • 10
    Примечание: это работает правильно, только если запуск скрипта занимает менее секунды
  • 1
    Рубо - если выполнение задания занимает секунды (а не милли или микросекунды), то вы не будете запускать его каждые тридцать секунд, чтобы иметь возможность запускаться два раза в минуту. Так что да, начните с 30, затем вычтите из этого приблизительное количество секунд на цикл, если оно больше 1 секунды.
10

Вы можете проверить мой ответ на этот похожий вопрос

В основном, я включил там сценарий bash под названием "runEvery.sh", который вы можете запускать cron каждые 1 минуту и передавать в качестве аргументов настоящую команду, которую вы хотите запустить, и частоту в секундах, в которой вы хотите ее запустить.

что-то вроде этого

* * * * * ~/bin/runEvery.sh 5 myScript.sh

8

Задача Cron не может использоваться для планирования задания в секундах. i.e Вы не можете планировать выполнение задания cron каждые 5 секунд. Альтернативой является запись оболочки script, которая использует в ней команду sleep 5.

Создайте оболочку script every-5-seconds.sh, используя bash while, как показано ниже.

$ cat every-5-seconds.sh
#!/bin/bash
while true
do
 /home/ramesh/backup.sh
 sleep 5
done

Теперь запустите эту оболочку script в фоновом режиме, используя nohup, как показано ниже. Это приведет к выполнению script даже после выхода из сеанса. Это выполнит вашу оболочку backup.sh script каждые 5 секунд.

$ nohup ./every-5-seconds.sh &
  • 3
    Время будет дрейфовать. Например, если для backup.sh требуется 1,5 секунды, он будет выполняться каждые 6,5 секунд. Есть способы избежать этого, например sleep $((5 - $(date +%s) % 5))
  • 0
    Я новичок в nohup, выполняя ваш пример, nohup возвращает «нет такого файла или каталога». После некоторых поисков вы, похоже, пропустили 'sh' после nohup. Вот так: $ nohup sh ./every-5-seconds.sh &
6

в /etc/cron.d/

new создать файл excute_per_30s

* * * * * yourusername  /bin/date >> /home/yourusername/temp/date.txt
* * * * * yourusername sleep 30; /bin/date >> /home/yourusername/temp/date.txt

будет работать cron каждые 30 секунд

6

Используйте часы:

$ watch --interval .30 script_to_run_every_30_sec.sh
  • 0
    $ watch --interval .10 php some_file.php я использовать что-то вроде $ watch --interval .10 php some_file.php ? или watch работают только с .sh файлами?
4

Задача Crontab может использоваться для планирования задания в минутах/часах/днях, но не в секундах. Альтернатива:

Создайте script для выполнения каждые 30 секунд:

#!/bin/bash
# 30sec.sh

for COUNT in `seq 29` ; do
  cp /application/tmp/* /home/test
  sleep 30
done

Используйте crontab -e и crontab для выполнения этого script:

* * * * * /home/test/30sec.sh > /dev/null
  • 1
    если я правильно понимаю, этот скрипт выполняется 30 раз и ждет 30 секунд между каждой итерацией. Как имеет смысл запускать его каждую минуту в cron?
4

Использовать fcron (http://fcron.free.fr/) - дает вам детализацию в секундах и пути лучше и богаче функций, чем cron (vixie-cron) и стабильный тоже. Я делал такие глупые вещи, как около 60 php-скриптов, работающих на одной машине, в очень глупых настройках, и он все еще выполнял свою работу!

  • 0
    Признания разработчика PHP; )
  • 1
    На самом деле, признания системного инженера, позволяющие разработчикам PHP .... :)
1

Спасибо за все хорошие ответы. Чтобы сделать это простым, мне понравилось смешанное решение, с контролем над crontab и временным разделением на скрипт. Так вот что я сделал, чтобы запустить скрипт каждые 20 секунд (три раза в минуту). Линия Crontab:

 * * * * 1-6 ./a/b/checkAgendaScript >> /home/a/b/cronlogs/checkAgenda.log

Автор сценария:

cd /home/a/b/checkAgenda

java -jar checkAgenda.jar
sleep 20
java -jar checkAgenda.jar 
sleep 20
java -jar checkAgenda.jar 
0

Если вы используете новейшую ОС Linux с SystemD, вы можете использовать SystemD Timer для запуска своего скрипта на любом уровне детализации, который вы хотите (теоретически до наносекунд), и - если хотите - гораздо более гибкие правила запуска, чем когда-либо допускал Cron, Не требуется sleep

Требуется немного больше для настройки, чем одна строка в файле cron, но если вам нужно что-то лучше, чем "каждую минуту", это стоит того.

Модель таймера SystemD в основном такова: таймеры - это единицы, которые запускают сервисные блоки, когда таймер истекает.

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

Вот простой пример, который регистрирует "Hello World" каждые 10 секунд:

/etc/systemd/system/helloworld.service:

[Unit]
Description=Say Hello
[Service]
ExecStart=/usr/bin/logger -i Hello World

/etc/systemd/system/helloworld.timer:

[Unit]
Description=Say Hello every 10 seconds
[Timer]
OnBootSec=10
OnUnitActiveSec=10
AccuracySec=1ms
[Install]
WantedBy=timers.target

После настройки этих устройств (в /etc/systemd/system, как описано выше, для общесистемного параметра или в ~/.config/systemd/user для настройки для конкретного пользователя) вам необходимо включить таймер ( а не сервис), запустив systemctl enable helloworld.timer. Если вы хотите немедленно запустить таймер (вместо того, чтобы ждать его запуска после перезагрузки), также запустите systemctl start helloworld.timer.

Используемые здесь секции раздела [Timer]:

  • OnBootSec - запустите службу через несколько секунд после каждой загрузки.
  • OnUnitActiveSec - запустить службу через много секунд после последнего запуска службы. Это то, что заставляет таймер повторять себя и вести себя как работа cron.
  • AccuracySec - устанавливает точность таймера. Таймеры только точные, как это поле устанавливает, и по умолчанию 1 минута (эмулирует cron). Основная причина не требовать лучшей точности - это повысить энергопотребление - если SystemD может планировать следующий прогон, чтобы он совпал с другими событиями, ему нужно было бы разбудить процессор реже. 1 1ms в приведенном выше примере не является идеальным - я обычно устанавливаю точность до 1 (1 секунду) в моих запланированных заданиях на подминутное время, но это будет означать, что если вы посмотрите на журнал с сообщениями "Hello World", видеть, что он часто задерживается на 1 секунду. Если вы в порядке с этим, я предлагаю установить точность до 1 секунды или более.

Как вы могли заметить, этот таймер не очень хорошо имитирует Cron - в том смысле, что команда не запускается в начале каждого периода настенных часов (т.е. Она не начинается на 10-й секунде на часах, затем 20 и т.д.). Вместо этого происходит только тогда, когда таймер сбрасывается. Если система загрузится в 12:05:37, то в следующий раз команда будет работать в 12:05:47, затем в 12:05:57 и т.д. Если вас интересует фактическая точность настенных часов, вы можете хотите заменить OnBootSec и OnUnitActiveSec и вместо этого установить правило OnCalendar с расписанием, которое вы хотите (насколько я понимаю, не может быть быстрее, чем 1 секунда, используя формат календаря). Вышеприведенный пример также может быть записан как:

OnCalendar=*-*-* *:*:00,10,20,30,40,50

Последнее примечание: как вы, наверное, догадались, блок helloworld.timer запускает модуль helloworld.service потому что у них одно и то же имя (минус суффикс типа единицы). Это значение по умолчанию, но вы можете переопределить это, установив поле Unit для раздела [Timer].

Более подробные сведения можно найти по адресу:

0

В настоящее время я использую метод ниже. Работает без проблем.

* * * * * /bin/bash -c ' for i in {1..X}; do YOUR_COMMANDS ; sleep Y ; done '

Если вы хотите запускать каждые N секунд, тогда X будет 60/N, а Y будет N.

Спасибо.

0

написать один скрипт оболочки. создать файл.sh

nano every30second.sh

и писать сценарий

#!/bin/bash
For  (( i=1; i <= 2; i++ ))
do
    write Command here
    sleep 30
done

затем установите cron для этого скрипта crontab -e

(* * * * */home/username/every30second.sh)

этот cron вызывает.sh файл каждые 1 мин и в.sh файле команду запускается 2 раза за 1 мин.

если вы хотите запустить скрипт в течение 5 секунд, замените 30 на 5 и измените для цикла следующим образом: For (( i=1; я <= 12; i++ ))

когда вы выбираете для любой секунды, затем вычисляете 60/ваш второй и записываете в цикл For

0

У меня была аналогичная задача, и я использовал следующий подход:

nohup watch -n30 "kill -3 NODE_PID" &

Мне нужно было периодически убивать -3 (чтобы получить трассировку стека программы) каждые 30 секунд в течение нескольких часов.

nohup ... & 

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

-1

Выполнить в цикле оболочки, например:

#!/bin/sh    
counter=1
while true ; do
 echo $counter
 counter=$((counter+1))
 if [[ "$counter" -eq 60 ]]; then
  counter=0
 fi
 wget -q http://localhost/tool/heartbeat/ -O - > /dev/null 2>&1 &
 sleep 1
done
  • 0
    Даже если предположить , что 60 должно быть 30 , вы можете переместить эту wget внутри , if заявление, в противном случае он выполняется каждый второй. В любом случае, я не уверен, насколько это лучше, чем просто один sleep 30 . Если бы вы отслеживали фактическое время UNIX, а не счетчик, это имело бы значение.
  • 0
    эх распечатав счетчик, вы можете узнать время задержки команды EXCUTE COMMAND, если не запустить wget в фоновом режиме.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню