Задать вопрос

Как средствами php запустить выполнение linux-команды в фоновом режиме?

Для запуска скриптов на сервере в фоновом режиме я обычно использую команду nohup. Я попробовал вызвать её через exec и shell_exec без дополнительных параметров. При запуске команды скрипт зависает до того момента, пока команда не выполнится. Ниже код команды:

exec('nohup rsync -avz -e "ssh -p 22 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" user1@3.3.3.3:/original/ /destination/s_24/ && echo $? >> /destination/l_24.txt 2>&1 &');


Так как же мне запустить rsync в фоновом режиме средствами php так, чтобы скрипт не ждал пока выполнится команда?

Важные уточнения/наблюдения

1. PHP-скрипт запускается из браузера, а не из терминала
2. PHP работает через php-fpm, т.е. без Apache

Я заменил фоновую команду на упрощенную для анализа проблемы. Следующие варианты вешают скрипт:

sleep 15 &
nohup sleep 15 &
setsid sleep 15 &


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

Тем не менее варианты:
nohup sleep 15 && exit &
nohup sleep 15 & exit

тоже не работают как надо.

Я также пробовал заменять exec на shell_exec, но это не дало никакого результата.
  • Вопрос задан
  • 1631 просмотр
Подписаться 6 Средний 7 комментариев
Решения вопроса 1
alekciy
@alekciy
Вёбных дел мастер
Самое главное что нужно сделать это перенаправить stdout команды из nohup (через > к примеру). Упрощенный пример. Запускаем в фоне печать DA через 10 секунд после запуска без блокирования php процесса:
exec("nohup sh -c 'sleep 10 && echo \"DA\"' > nohup.php.out 2>&1 &");

Пример запуска:
$ date +%X
17:15:32
$ php -f test.php && date +%X && tail -F nohup.php.out
17:15:34
DA
^C
$ date +%X
17:15:45
$
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@MadridianFox
Web-программист, многостаночник
nohup - это команда bash, которая просто указывает самому bash'у что фоновому процессу не надо отправлять сигнал HUP при завершении работы.
& это тоже фишка bash, позволяющая перевести процесс в фон

Проблема в том что php это вам не bash и он наверное сам отслеживает состояние запущенного им процесса.

Попробуйте использовать setsid.
В отличие от nohup это полноценная программа, которая запускает указанную в качестве аргумента программу в отдельной сессии. Как только целевая программа запущена setsid завершает работу. Это должно "отпустить" php почти моментально.
Ответ написан
@karpo518 Автор вопроса
Ещё раз всё проверил и написал костыль... Считаю проблему нерешенной =(

Подробности


Итоговые выводы:

Чтобы запустить команду асинхронно, нужно:

1. Перенаправить основной поток вывода из консоли (в /dev/null или файл)
2. Использовать после команды символ &

nohup и другие дополнительные команды не нужны

В моем случае это всё не сработало. Мне требуется получить код выхода rsync. По какой-то причине этот код не попадает ни stdout, ни в stderr. В итоге мне пришлось использовать конструкцию:

rsync params && echo $? >> /log.txt 2>&1 &

Именно эта конструкция по какой-то причине не работает асинхронно.

Чтобы код заработал асинхронно, потребовалось создать прослойку в виде bash-скрипта:

#!/bin/bash

rsync -avz -e "ssh -p $2 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" $3@$1:$4 $5 >> $6 2>&1

echo $? >> $6

# rsync_download.sh sshHost sshPort sshLogin target destinity logPath


И запускать её асинхронно:

$command = $shDir . "rsync_download.sh $sshHost $sshPort $sshLogin $directory $snapshotPath $logPath > /dev/null 2>&1 &";

exec($command);


Это ужасное и громоздкое решение. Если кто-то сможет объяснить причину проблемы и подсказать аккуратное решение без bash-скрипта, буду очень благодарен.

Тестовый пример, который подтверждает проблему с echo:

exec('grep -r "user" /folder/ && echo $? >> /home/user1/web/backuper.ru/web/log.txt 2>&1 &');

Ответ написан
@Tibor128
попробуйте daemon
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы