PID процессов index.php: методы администрирования
Управление PID процессов в системном администрировании
Наиболее эффективное решение: поиск PID с помощью pgrep
Команда pgrep позволяет найти PID процесса по имени или шаблону, исключая ложные срабатывания. Для скрипта index.php выполняется:
pgrep -f 'index.php'
Опция -f ищет совпадение во всей командной строке, что важно, если процесс запущен с аргументами. Если нужно только точное имя исполняемого файла, используется pgrep -x 'php'.
Проблемы: при множестве процессов index.php выводятся все PID. Решение - фильтрация через pgrep -f 'php /path/to/index.php'.
Типичная ошибка: pgrep не установлен в системе. Установка: apt install procps (Debian/Ubuntu) или yum install procps-ng (CentOS/RHEL).
Как сохранить PID запущенного процесса для последующего контроля?
При запуске фонового процесса PID передается в переменную $!. Сохранение в файл .pid:
/usr/bin/php /var/www/index.php &
echo $! > /var/run/myindex.pid
При завершении процесса файл следует удалять, чтобы избежать «зависших» pid-файлов. Используется trap:
#!/bin/bash
PIDFILE=/var/run/myindex.pid
trap "rm -f $PIDFILE; exit" SIGTERM SIGINT
/usr/bin/php /var/www/index.php &
echo $! > $PIDFILE
wait
Проблема: если процесс убит принудительно (kill -9), trap не срабатывает. Альтернатива - очистка при старте или использование утилиты pidfile.
Как проверить, работает ли процесс по сохранённому PID?
Сигнал 0 (kill -0 PID) проверяет существование процесса без отправки сигнала. Пример:
PID=$(cat /var/run/myindex.pid)
if kill -0 $PID 2>/dev/null; then
echo "Процесс работает"
else
echo "Процесс не найден"
fi
Если PID не существует или нет прав, kill -0 возвращает ошибку. Альтернатива - проверка каталога /proc/PID:
[ -d /proc/$PID ] && echo "Работает" || echo "Не работает"
Ошибка: PID может быть переиспользован ядром после завершения процесса. Для критичных сценариев рекомендуется дополнительно проверять имя процесса через /proc/$PID/cmdline.
Как завершить процесс по PID с гарантией?
Обычное завершение: kill 1234 (SIGTERM). Принудительное: kill -9 1234 (SIGKILL). Для поиска и убийства всех процессов index.php:
pkill -f 'index.php'
Или killall -9 index.php (если имя точно совпадает). Для одного процесса из группы - fuser по файлу или порту.
Типичная ошибка: попытка убить процесс с PID, который уже не существует. Всегда проверяйте сначала kill -0.
Как получить PID из самого PHP-скрипта?
Функция posix_getpid() возвращает PID текущего процесса. Пример записи в лог:
<?php
$pid = posix_getpid();
file_put_contents('/var/log/index_pid.log', $pid, FILE_APPEND);
?>
Альтернатива: getmypid() - работает только в CLI-режиме. При использовании в веб-сервере (mod_php) PID будет принадлежать рабочему процессу Apache/Nginx.
Проблема: в многопоточных окружениях posix_getpid() возвращает PID процесса, а не потока. Для потоков используется getmypid() не поддерживается.
Как управлять группой процессов для фоновых задач?
Фоновые процессы можно объединить в группы с помощью setsid или setpgid. Пример запуска с новой сессией:
setsid /usr/bin/php /var/www/index.php &
Это позволит завершить всю группу через kill -PID с отрицательным значением: kill -- -$(cat /var/run/myindex.pid).
Ошибка: при использовании setsid PID группы отличается от PID процесса. Для работы с группой нужно сохранять PGID, получаемый через ps -o pgid= -p $PID.
Расширенные примеры работы с PID процессов index.php
Пример 1: Скрипт мониторинга с перезапуском
Сценарий: запускать index.php как демон, проверять его существование каждые 10 секунд и перезапускать при падении.
#!/bin/bash
PIDFILE=/var/run/index.pid
SCRIPT=/var/www/index.php
start() {
/usr/bin/php $SCRIPT &
echo $! > $PIDFILE
echo "Запущен процесс с PID $(cat $PIDFILE)"
}
stop() {
if [ -f $PIDFILE ]; then
PID=$(cat $PIDFILE)
kill -0 $PID 2>/dev/null && kill $PID
rm -f $PIDFILE
fi
}
monitor() {
while true; do
if [ ! -f $PIDFILE ] || ! kill -0 $(cat $PIDFILE) 2>/dev/null; then
echo "Процесс не работает. Перезапуск..."
start
fi
sleep 10
done
}
case "$1" in
start) start ;;
stop) stop ;;
monitor) monitor ;;
restart) stop; start ;;
*) echo "Использование: $0 {start|stop|restart|monitor}" ;;
esac
Результат выполнения (при старте):
$ ./index_manager.sh start Запущен процесс с PID 12345 $ ps aux | grep index user 12345 0.5 1.2 56789 1234 ? S 10:00 0:00 /usr/bin/php /var/www/index.php
Пример 2: Получение PID через /proc с проверкой имени и состояния
Использование /proc для верификации, что PID действительно принадлежит нужному скрипту.
#!/bin/bash
PID=$1
if [ -d /proc/$PID ]; then
CMDLINE=$(cat /proc/$PID/cmdline | tr '\0' ' ')
if [[ "$CMDLINE" == *"index.php"* ]]; then
STATE=$(cat /proc/$PID/status | grep '^State:' | awk '{print $2}')
echo "Процесс $PID: $STATE"
else
echo "PID $PID не относится к index.php"
fi
else
echo "PID $PID не существует"
fi
Результат:
$ ./check_pid.sh 12345 Процесс 12345: S (sleeping) $ ./check_pid.sh 9999 PID 9999 не существует
Пример 3: Использование PHP для поиска PID собственного процесса и его родителя
Внутри скрипта можно получить не только свой PID, но и PID родительского процесса (PPID).
<?php
$pid = posix_getpid();
$ppid = posix_getppid();
echo "Текущий PID: $pid\n";
echo "PID родителя: $ppid\n";
// Рекурсивный поиск всех дочерних процессов
$children = exec("ps --ppid $pid -o pid= | tr '\n' ' '");
echo "Дочерние PID: $children\n";
?>
Вывод при запуске:
$ php /var/www/index.php Текущий PID: 24680 PID родителя: 24679 Дочерние PID: 24681 24682
Пример 4: Безопасное убийство процесса с использованием fuser и файловых блокировок
Если скрипт открывает файл, fuser находит процессы по файлу. Команда убивает все процессы, держащие файл.
#!/bin/bash
PIDFILE=/var/run/index.pid
LOCKFILE=/var/lock/index.lock
# Создание блокировки с помощью flock
exec 200>$LOCKFILE
flock -x 200
# Запуск с записью PID
/usr/bin/php /var/www/index.php &
echo $! > $PIDFILE
# При остановке: убить процессы, держащие PIDFILE
fuser -k -TERM $PIDFILE
# Или убить по PID из файла
if [ -f $PIDFILE ]; then
kill $(cat $PIDFILE) 2>/dev/null || true
rm -f $PIDFILE
fi
flock -u 200
Результат fuser:
$ fuser /var/run/index.pid /var/run/index.pid: 12345
Пример 5: Мониторинг с использованием inotifywait (уведомления о завершении)
Отслеживание завершения процесса через /proc неэффективно. Использование inotify на файле состояния.
#!/bin/bash
PIDFILE=/var/run/index.pid
# Ждем, пока процесс завершится, наблюдая за /proc
while [ -d /proc/$(cat $PIDFILE) ]; do
sleep 1
done
echo "Процесс $(cat $PIDFILE) завершился"
Но лучше использовать wait в родительском shell, если процесс был запущен в том же сеансе. Альтернатива - использование strace для отладки:
strace -p $(cat /var/run/index.pid) -e trace=exit,exit_group 2>&1 | head -5
Результат strace (при завершении):
exit_group(0) = ? +++ exited with 0 +++