Почему процессы, порожденные cron, в конечном итоге перестают функционировать?

StackOverflow https://stackoverflow.com/questions/1506902

Вопрос

У меня есть некоторые процессы, которые отображаются как <defunct> в topps).Я сварил все на основе реальных сценариев и программ.

В моем crontab:

* * * * * /tmp/launcher.sh /tmp/tester.sh

Содержание launcher.sh (который, конечно, помечен как исполняемый):

#!/bin/bash
# the real script does a little argument processing here
"$@"

Содержание tester.sh (который, конечно, помечен как исполняемый):

#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background

ps показывает следующее:

user       24257 24256  0 18:32 ?        00:00:00 [launcher.sh] <defunct>
user       24259     1  0 18:32 ?        00:00:00 sleep 27

Обратите внимание , что tester.sh не отображается - он завершает работу после запуска фонового задания.

Почему это происходит launcher.sh оставайтесь поблизости с пометкой <defunct>?Кажется, что он делает это только при запуске cron-- не тогда, когда я управляю им сам.

Дополнительное примечание: launcher.sh это обычный скрипт в системе, на котором он запускается, который нелегко изменить.Другие вещи (crontab, tester.sh, даже программа , которую я запускаю вместо sleep) может быть изменен гораздо проще.

Это было полезно?

Решение

Потому что они не были предметом wait(2) системный вызов.

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

Когда вы запускаете его из командной строки, ваша оболочка все равно захватывает SIGCHLD и выполняет различные операции ожидания, так что ничто не остается неработоспособным надолго.

Но cron не находится в состоянии ожидания, он спит, поэтому несуществующий дочерний элемент может оставаться рядом некоторое время, пока cron не проснется.


Обновить:   Отвечаю на комментарий...Хм.Мне действительно удалось продублировать проблему:

 PPID   PID  PGID  SESS COMMAND
    1  3562  3562  3562 cron
 3562  1629  3562  3562  \_ cron
 1629  1636  1636  1636      \_ sh <defunct>
    1  1639  1636  1636 sleep

Итак, я думаю, что произошло вот что:

  • cron разветвляется, и дочерний элемент cron запускает оболочку
  • оболочка (1636) запускает sid и pgid 1636 и переходит в режим ожидания
  • оболочка завершает работу, SIGCHLD отправляется в cron 3562
  • сигнал игнорируется или неправильно обрабатывается
  • шелл превращается в зомби.Обратите внимание, что режим sleep перенаправляется на init, поэтому при выходе из режима sleep init получит сигнал и выполнит очистку.Я все еще пытаюсь выяснить, когда пожнут зомби.Вероятно, при отсутствии активных дочерних элементов cron 1629 выясняет, что он может завершиться, в этот момент зомби будет переведен в init и получит reaped.Итак, теперь мы задаемся вопросом об отсутствующем SIGCHLD, который cron должен был обработать.
    • Это не обязательно вина викси крон.Как вы можете видеть здесь, libdaemon устанавливает обработчик SIGCHLD во время daemon_fork(), и это может помешать доставке сигнала при быстром выходе промежуточным 1629

      Теперь я даже не знаю, собран ли vixie cron в моей системе Ubuntu с помощью libdaemon, но, по крайней мере, у меня есть новая теория.:-)

Другие советы

Я подозреваю, что Крон ждет всех подпроцессов в сессии, чтобы прекратить. См. Подождите (2) в отношении отрицательных аргументов PID. Вы можете увидеть Sess с:

ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm

Вот что я вижу (отредактировано):

STAT  EUID  RUID TT       TPGID  SESS  PGRP  PPID   PID %CPU COMMAND
Ss       0     0 ?           -1  3197  3197     1  3197  0.0 cron
S        0     0 ?           -1  3197  3197  3197 18825  0.0  \_ cron
Zs    1000  1000 ?           -1 18832 18832 18825 18832  0.0      \_ sh <defunct>
S     1000  1000 ?           -1 18832 18832     1 18836  0.0 sleep

Обратите внимание, что SH и сон находятся в том же SESS.

Используйте командный набор (1). Вот тестор .sh:

#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background

Заметьте, что вам не нужно &, SetSID помещает его на задний план.

На мой взгляд, это вызвано процессом Crond (порожденным Crond для каждой задачи) в ожидании ввода на stdin, который приводится к Stdout/Stderr команды в Crontab. Это сделано, потому что Cron может отправлять полученный результат по почте пользователю.

Таким образом, Кронд ждет EOF до команды пользователя, и все его порожденные дочерние процессы закрыли трубу. Если это сделано, Crond продолжается с помощью ожидания, а тогда несуществующая команда пользователя исчезает.

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

Таким образом, следующая строка должна работать в Crontab:

* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & ) 

Я бы порекомендовал вам решить проблему, просто не имея двух отдельных процессов: иметь launcher.sh Сделайте это на последней строке:

exec "$@"

Это устранит лишний процесс.

Я нашел этот вопрос, пока искал решение с аналогичной проблемой. К сожалению, ответы в этом вопросе не решили мою проблему.

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

ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh

В «grep» вы можете сузить поиск до определенного несуществующего процесса, который вы хотите.

Я так много раз тестировал ту же проблему. И, наконец, у меня есть решение. Просто укажите «/bin/bash» перед сценарием Bash, как показано ниже.

* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top