Запустив две команды Linux через PHP, не ждите, пока первый завершится, прежде чем выполнять вторую

Это довольно странно, и я искал и пробовал все, но я думаю, что я просто делаю глупую синтаксическую ошибку здесь.

Я пытаюсь запустить стресс-тест на процессоре, а затем сразу ограничить его использование процессора до 30%, и все это через PHP. Тест также запускается под другим пользователем и с указанным именем, поэтому его можно ограничить. Стресс-тест начинается нормально, но я вижу, что файл PHP все еще загружается, и он заканчивается, как только заканчивается стресс-тест.

Вот несколько способов, которыми я пытался это сделать.

$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30"');

$output = exec('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s > /dev/null & cpulimit -e MyUniqueProcessName -l 30"');

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

редактировать::

вот что у меня сейчас:

Мне нужно запустить стресс под «test», но cpulimit под sudo apache или root, потому что он требует специальных разрешений. Стресс все еще начинается нормально, но съедает 99,9%

passthru('sudo runuser -l test -c "exec -a MyUniqueProcessName stress -c 1 -t 60s &" & sudo cpulimit -e MyUniqueProcessName -l 30 -i -z');

Я не вижу cpulimit в списке процессов после выполнения этого http://i.imgur.com/iK2nL43.png

1

Решение

К сожалению, && делает более или менее противоположное тому, что вы хотите. 🙂 Когда вы делаете A && B в Bash это означает: «Запустите команду A и подождите, пока она не будет выполнена; если это удалось, то запустите команду B.»

В отличие от A & B означает «Выполнить команду A, а затем немедленно запустить команду B.»

Таким образом, вы почти правы в своей команде, но просто запутались, используя два bash команды (должна быть только одна) и &&,

Кроме того, вы пытались запустить каждую команду отдельно, вне PHP, в двух терминалах? Я только что скачал и собрал оба стресс а также CPULimit (Я предполагаю, что это те, которые вы используете?), Запустил команды отдельно и обнаружил проблему: cpulimit все еще не ограничивает процент.

Глядя на документы для stressЯ вижу, что это работает путем разветвления дочерних процессов, поэтому тот, который вы пытаетесь ограничить ЦП, является родительским, но это не тот, который использует ЦП. cpulimit --help показывает, что есть вариант -i, который включает дочерние процессы в то, что ограничено.

Это приводит меня к тому, что я могу ввести это в одном терминале (первая строка показывает ввод в приглашении; последующий вывод вывода):

$> exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i
[1] 20229
MyUniqueProcessName: info: [20229] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
Process 20229 found

Затем в другом терминале работает top, Я вижу:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
20237 stackov+  20   0  7164  100    0 R 30.2  0.0   0:04.38 stress

Намного лучше. (Обратите внимание, что за пределами оболочки Bash, где вы добавили exec -a, вы увидите имя процесса как stressК сожалению, я также вижу другую проблему, которая cpulimit оставаясь «слушающим» больше процессов с этим именем. Вернуться к cpulimit --help, который раскрывает -z вариант.

Чтобы немного уменьшить сложность, вы можете оставить псевдоним выключенным и использовать PID stress обрабатывать, используя специальную переменную Bash $!, который ссылается на PID последнего запущенного процесса. Запуск следующего в терминале, кажется, делает все, что вы хотите:

stress -c 1 -t 60s & cpulimit -p $! -l 30 -i -z

Так что теперь, просто измените скрипт PHP на то, что мы узнали:

exec('bash -c "exec -a MyUniqueProcessName stress -c 1 -t 60s & cpulimit -e MyUniqueProcessName -l 30 -i -z"');

…или, более простая версия:

exec('bash -c "stress -c 1 -t 60s & cpulimit -p \$! -l 30 -i -z"');

(Обратите внимание на $ в $! пришлось избежать обратной косой черты, \$!из-за того, как он цитируется при передаче bash -c.)

Окончательный ответ:

Основываясь на последнем примере, который вы внесли в свой вопрос, вы захотите что-то вроде этого:

passthru('bash -c "sudo -u test stress -c 1 -t 60s & sudo -u root cpulimit -p \$! -l 30 -i -z"');

Когда я запускаю это с php stackoverflow-question.php, он выводит следующее:

stress: info: [3374] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
stress: info: [3374] successful run completed in 60s
Process 3371 found

(Вторые две строки только появляются после завершения PHP-скрипта, так что не вводите в заблуждение. использование top Проверять.)

Бег top в другом терминале в течение 60 секунд работает скрипт PHP, я вижу:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
3472 test      20   0  7160   92    0 R 29.5  0.0   0:07.50 stress
3470 root       9 -11  4236  712  580 S  9.0  0.0   0:02.28 cpulimit

Это именно то, что вы описали, желая: stress работает под пользователем test, а также cpulimit работает под пользователем root (оба из которых вы можете изменить в команде, если это необходимо). stress ограничено до 30%.

Я не знаком с runuser и не вижу применимости, так как sudo это стандартный способ запуска процесса от имени другого пользователя. Чтобы заставить это работать, вам, возможно, придется скорректировать ваши настройки в / etc / sudoers (для этого потребуется доступ с правами root, но у вас, очевидно, это уже есть). Это полностью выходит за рамки этого обсуждения, но в качестве примера я добавил следующие правила:

my-user ALL=(test) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/stress
my-user ALL=(root) NOPASSWD:NOEXEC: /home/my-user/development/stackoverflow/cpulimit
0

Другие решения

Других решений пока нет …