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 +++

PID процессов - comments

En
Index php pid (php)