Безумное поведение Кронда. продолжает делать несуществующие процессы bash

У меня есть crontab, который выглядит так:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php >> /dev/null &

Максимально просто, правда?

zdaemon.php, который я только что тестировал:

#!/usr/bin/php
<?


while(true){
        sleep(1);
}

?>

Всякий раз, когда он запускается, он зависает, как:

root     15532  0.0  0.1 57228 1076 ?        Ss   19:09   0:00 crond
root     16681  0.0  0.1 72196 1428 ?        S    21:46   0:00 crond
root     16682  0.0  0.0     0    0 ?        Zs   21:46   0:00 [bash] <defunct>
root     16683  0.0  0.5 54800 5740 ?        S    21:46   0:00 /usr/bin/php /var/www/html/private/fivemin/zdaemon.php
root     16687  0.0  0.1 72196 1428 ?        S    21:47   0:00 crond
root     16688  0.0  0.0     0    0 ?        Zs   21:47   0:00 [bash] <defunct>
root     16689  0.0  0.5 54800 5740 ?        S    21:47   0:00 /usr/bin/php /var/www/html/private/fivemin/zdaemon.php

Я весь день билась головой об стену по этому поводу. Кто-нибудь видел это раньше? Есть идеи вообще?

Это ссылка на: зависание сценария Init.d


person ehiller    schedule 20.09.2010    source источник


Ответы (4)


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

Происходит следующее: cron интересуется stderr из сценария, который он запускает (чтобы он мог отправить его вам по электронной почте в случае сбоя сценария), поэтому он создает канал который присоединяет stderr скрипта для записи конца (дескриптор файла 2). Затем cron приступает к чтению на считываемом конце канала, ожидая, пока скрипт завершит работу и прочитает eof (read() из нулевых байтов) — затем он получает статус возврата скрипта.

В вашем примере порожденный демон наследует файловый дескриптор stderr, и поэтому, когда промежуточная оболочка выходит (и перестает функционировать), демон удерживает канал открытым. Поэтому cron никогда не читает eof и, следовательно, никогда не получает статус возврата.

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

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php >> /dev/null 2>&1 &

который запишет оба stdout и stderr в /dev/null

person Beano    schedule 20.09.2010
comment
Это потрясающе!! Это был 100% stderr, который меня портил. Я изменил строку на: $LDIR/$EXEC &› $LDIR/swapi.log & MYPID=$! в моем скрипте init.d (см. другой постинг) и теперь все работает как надо. Спасибо Спасибо спасибо!!! - person ehiller; 20.09.2010

Я думаю, что ваша основная проблема заключается в том, что stderr все еще отправляется в оболочку, но дочерний процесс (ваш php-процесс) спит, что приводит к процессу зомби. Попробуй это:

0-59 * * * * /var/www/html/private/fivemin/zdaemon.php &> /dev/null &

Если у вас по-прежнему возникают проблемы с зомби-процессом, взгляните на nohup.

person Mike Axiak    schedule 20.09.2010

Мне кажется странным запускать процесс в crontab. Попробуйте удалить & в конце строки.

person Dennis Williamson    schedule 20.09.2010

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

Я не делал этого в php, но вы можете использовать pcntl_fork() чтобы имитировать обычный способ c.

person grossvogel    schedule 20.09.2010
comment
следует отметить, что запуск демона с помощью fork() не тривиален, и вам обычно приходится дважды выполнять fork, чтобы сделать это правильно. - person Mike Axiak; 20.09.2010