Почему процессы, порожденные cron, заканчиваются несуществующими?
у меня есть некоторые процессы отображаются как <defunct>
на top
(и ps
). Я сварил все из реальных сценариев и программ.
в своем 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
не появляется--it вышел после запуска фонового задания.
почему launcher.sh
остаться, отмеченные <defunct>
? Кажется, это делается только при запуске cron
-- не тогда, когда я запускаю его сам.
дополнительная информация: launcher.sh
является общим скриптом в системе, на которой он работает, который нелегко изменить. Другие вещи (crontab
, tester.sh
, даже программа, которую я запускаю вместо sleep
) можно modiified гораздо легче.
6 ответов
потому что они не были предметом wait(2)
системный вызов.
поскольку кто-то может ждать этих процессов в будущем, ядро не может полностью избавиться от них или не сможет выполнить wait
системный вызов, потому что он больше не будет иметь статуса выхода или доказательства его существования.
когда вы запускаете один из оболочки, ваша оболочка захватывает SIGCHLD и выполняет различные операции ожидания в любом случае, поэтому ничто не остается несуществующим для длинный.
но крон не в состоянии ожидания, он спит, поэтому несуществующий ребенок может остаться на некоторое время, пока крон не проснется.
обновление: отвечая на замечание... Хм. Мне удалось дублировать проблему:
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 ребенок начинает shell
- shell (1636) запускает sid и pgid 1636 и начинает спать
- оболочка выходит, SIGCHLD отправлено в cron 3562
- сигнал игнорируется или неправильно обрабатывается
- shell превращает зомби. Обратите внимание, что сон возвращается в init, поэтому, когда сон выходит из init, он получит сигнал и очистится. Я все еще пытаюсь понять, когда зомби пожнут. Вероятно, без активных детей cron 1629 выясняет, что он может выйти, в этот момент зомби будет переродиться в init и получить жатву. Итак, теперь мы задаемся вопросом о пропавшем SIGCHLD, который должен был иметь cron обработанный.
- это не обязательно вина Викси крон. Как вы можете видеть здесь, libdaemon устанавливает обработчик SIGCHLD во время
daemon_fork()
, и это может помешать доставке сигнала на быстром выходе промежуточным 1629теперь я даже не знаю, построен ли vixie cron в моей системе Ubuntu с libdaemon, но, по крайней мере, у меня есть новая теория. :-)
- это не обязательно вина Викси крон. Как вы можете видеть здесь, libdaemon устанавливает обработчик SIGCHLD во время
Я подозреваю, что cron ждет завершения всех подпроцессов в сеансе. См. wait (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
используйте команду setsid (1). Вот tester.sh:
#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background
обратите внимание, что вам не нужно &
, setsid ставит его в фоновом режиме.
Я бы рекомендовал вам решить проблему, просто не имея двух отдельных процессов: Have launcher.sh
сделайте это в последней строке:
exec "$@"
Это исключит излишний процесс.
на мой взгляд, это вызвано процессом CROND (порожденным crond для каждой задачи), ожидающим ввода на stdin, который передается в stdout/stderr команды в crontab. Это делается потому, что cron-это возможность отправлять результат по почте пользователю.
таким образом, CROND ждет EOF, пока команда пользователя и все порожденные дочерние процессы не закроют канал. Если это сделано, CROND продолжает оператор wait, а затем команду несуществующего пользователя исчезает.
поэтому я думаю, что вам нужно явно отключить каждый порожденный подпроцесс в вашем скрипте из канала (например, перенаправив его в файл или /dev/null.
поэтому в crontab должна работать следующая строка:
* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & )
Я нашел этот вопрос, когда искал решение с аналогичной проблемой. К сожалению, ответы на этот вопрос не решили мою проблему.
убийство несуществующего процесса не является вариантом, поскольку вам нужно найти и убить его родительский процесс. Я закончил тем, что убил несуществующие процессы следующим образом:
ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",}' | sh
в "grep "" вы можете сузить поиск до определенного несуществующего процесса, который вам нужен.
Я тестировал одну и ту же проблему так много раз. И, наконец, я нашел решение. Просто укажите "/bin/bash " Перед сценарием bash, как показано ниже.
* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh