Убейте детей сценария bash переднего плана, когда придет сигнал - PullRequest
12 голосов
/ 24 ноября 2010

Я обертываю приложение fastcgi в bash-скрипт следующим образом:

#!/bin/bash
# stuff
./fastcgi_bin
# stuff

Поскольку bash выполняет только прерывания для сигналов, когда сценарий переднего плана заканчивается, я не могу просто kill -TERM scriptpid, потому что приложение fastcgi будет поддерживаться.
Я попытался отправить двоичный файл в фоновом режиме:

#!/bin/bash
# stuff
./fastcgi_bin &
PID=$!
trap "kill $PID" TERM
# stuff

Но если я делаю это так, очевидно, stdin и stdout не перенаправлены должным образом, поскольку они не соединяются с lighttpds mod_fastgi, версия переднего плана работает.

РЕДАКТИРОВАТЬ: Я смотрел на проблему, и это происходит потому, что bash перенаправляет / dev / null в stdin, когда программа запускается в фоновом режиме, поэтому любой способ избежать этого должен решить мою проблему а также.

Есть подсказка, как решить эту проблему?

Ответы [ 7 ]

16 голосов
/ 27 ноября 2010

Есть несколько вариантов, которые приходят мне в голову:

  • Когда процесс запускается из сценария оболочки, оба относятся к одной и той же группе процессов. Убийство родительского процесса оставляет детей живыми, поэтому следует убить всю группу процессов. Это может быть достигнуто путем передачи отрицательного PGID (ID группы процессов) в kill, который совпадает с PID родителя. ej: kill -TERM -$PARENT_PID

  • Не выполнять двоичный файл как ребенок, но заменяющий сценарий обработать с exec. Вы теряете способность выполнять вещи потом хотя, потому что exec полностью заменяет родительский процесс.

  • Не уничтожать процесс сценария оболочки, а двоичный код FastCGI. Затем в сценарии проверьте код возврата и действуйте соответствующим образом. например: ./fastcgi_bin || exit -1

В зависимости от того, как mod_fastcgi обрабатывает рабочие процессы, возможен только второй вариант.

1 голос
/ 01 февраля 2011

Я написал этот сценарий всего несколько минут назад, чтобы уничтожить сценарий bash и всех его дочерних элементов ...

#!/bin/bash
# This script will kill all the child process id for a  given pid
# based on http://www.unix.com/unix-dummies-questions-answers/5245-script-kill-all-child-process-given-pid.html

ppid=$1

if [ -z $ppid ] ; then
   echo "This script kills the process identified by pid, and all of its kids";
   echo "Usage: $0 pid";
   exit;
fi

for i in `ps j | awk '$3 == '$ppid' { print $2 }'`
do
    $0 $i   
    kill -9 $i
done

Убедитесь, что сценарий является исполняемым, иначе вы получите сообщение об ошибке $ 0 $ i.

1 голос
/ 27 ноября 2010

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

Не могли бы вы переписать скрипт bash на Perl? В Perl есть несколько методов управления дочерними процессами. Вы можете прочитать perldoc perlipc и другие подробности в основных модулях IPC::Open2 и IPC::Open3.

Я не знаю, как это будет взаимодействовать с lighttpd и т. Д. Или есть ли в этом подходе больше функциональности, но, по крайней мере, это дает вам больше гибкости и больше для чтения в вашей охоте.

0 голосов
/ 26 апреля 2013

Попробуйте сохранить оригинал stdin, используя ./fastcgi_bin 0<&0 &:

#!/bin/bash
# stuff
./fastcgi_bin 0<&0 &
PID=$!./fastcgi_bin 0<&0 &
trap "kill $PID" TERM
# stuff


# test
#sh -c 'sleep 10 & lsof -p ${!}'
#sh -c 'sleep 10 0<&0 & lsof -p ${!}'
0 голосов
/ 28 ноября 2010

Вы можете переопределить неявный </dev/null для фонового процесса, перенаправив stdin самостоятельно, например:

sh -c 'exec 3<&0; { read x; echo "[$x]"; } <&3 3<&- & exec 3<&-; wait'
0 голосов
/ 27 ноября 2010

Я не уверен, что полностью понял вашу точку зрения, но вот что я попробовал, и процесс, похоже, может управлять ловушкой (назовите это trap.sh):

#!/bin/bash

trap "echo trap activated" TERM INT
echo begin
time sleep 60
echo end

Запустите его:

./trap.sh &

И поиграть с ним (только одна из этих команд одновременно):

kill -9 %1
kill -15 %1

Или начать на переднем плане:

./trap.sh

И прервать с помощью управления-C.

Кажется, работает на меня.Что именно у вас не работает?

0 голосов
/ 24 ноября 2010

Вы можете сделать это с помощью сопроцесса .

Редактировать: ну, сопроцессы - это фоновые процессы, которые могут иметь открытые stdin и stdout (потому что bash готовит для них fifo).Но вам все равно нужно читать / писать в эти данные, и единственный полезный примитив для этого - bash read (возможно, с таймаутом или дескриптором файла);ничего достаточно надежного для CGI.Итак, если подумать, мой совет не делать этого в bash.Было бы удобнее выполнять дополнительную работу в fastcgi или в оболочке http, такой как WSGI.

...