2015-09-02 6 views
2

Мне нужно выполнить практически произвольные команды на (удаленной) оболочке в эфемерных контейнерах/виртуальных машинах для механизма выполнения тестов. Иногда эти процессы утечки, которые затем приводят к зависанию всей команды. Это может быть сводились к этой простой команды:shell: очистить протекающие фоновые процессы, зависающие из-за совместного использования stdout/stderr

$ sh -c 'sleep 30 & echo payload' 
payload 
$ 

Здесь представлена ​​справочная информация sleep 30 играет роль просочилась процесса (который на самом деле будет что-то вроде dbus-daemon) и эхо является фактическим, что я хочу работать. sleep 30 & echo payload следует рассматривать как атомную непрозрачную команду примера здесь.

Вышеуказанная команда в порядке и немедленно возвращается, так как stdout/stderr сна также являются PTY. Тем не менее, при захвате вывода команды в трубе/файл (тест бегун хочет сохранить все в журнал, в конце концов), вся команда зависание:

$ sh -c 'sleep 30 & echo payload' | cat 
payload 
# ... does not return to the shell (until the sleep finishes) 

Теперь, это может быть исправлено с некоторыми довольно смехотворно сложная оболочечная магия, которая определяет FDs stdout/err от /proc/$$/fd/{1,2}, итерации над ls /proc/[0-9]*/fd/* и убийства каждого процесса, который также имеет тот же stdout/stderr. Но это связано с большим количеством хрупкого кода оболочки и дорогостоящих сравнений строк оболочки.

Есть ли способ очистить эти пропущенные фоновые процессы более элегантным и простым способом? setsid не помогает:

$ sh -c 'setsid -w sh -c "sleep 30 & echo payload"' | cat 
payload 
# hangs... 

Обратите внимание, что группы процессов/сессии и их убийство оптовыми не является достаточным, как просочились процессы (например, Dbus-демон) часто setsid себя.

P.S. Я могу только предполагать оболочку POSIX или bash в этих средах; нет Python, Perl и т. д.

Спасибо заранее!

+0

Следующие работы, но я не могу ответить на этот вопрос: 'sh -c '{sleep 30 | Кот ; } & {echo полезная нагрузка | Кот ; } '' –

+0

Спасибо, но я специально не ищу решение для сна и эха; это всего лишь пример команды для ситуации «некоторая команда утечки фоновой команды». Я добавил некоторые разъяснения к вопросу. –

+0

Я нашел начальное приближение: '$ setsid -w sh -c 'sleep 30 & echo полезная нагрузка; RC = $ ?; для p в $ (pgrep --pgroup 0); do [$ p = $$] || kill $ p; сделанный; exit $ RC '| cat' Просто использование 'kill - - $$' слишком агрессивное, поскольку оно также убивает оболочку. –

ответ

0

У нас была эта проблема с параллельными тестами в Launchpad. Самое простое решение, с которым мы тогда работали, - это просто убедиться, что никакие процессы не разделяют stdout/stdin/stderr (кроме тех, где вы действительно хотите висеть, если они еще не закончены - например, сами испытательные рабочие).

0

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

Другой вариант, не идеальный, но полезный, - стать местным жатки с prctl (2) и PR_SET_CHILD_SUBREAPER. Это позволит вам стать родителем всех процессов, которые в противном случае были бы готовы к init. С помощью этой схемы вы можете попытаться убить все процессы, которые у вас есть ppid. Это ужасно, но это самая лучшая вещь для использования групп.

Но обратите внимание, что если вы не используете этот помощник как root, вы обнаружите, что практическое тестирование может породить некоторую вещь setuid, которая будет скрываться и не будет убивать. Это действительно раздражающая проблема.

+0

Для той же проблемы у нас есть в plainbox (еще один инструмент тестирования ;-) Вы можете посмотреть эта ошибка https://bugs.launchpad.net/plainbox/+bug/1377270, но все детали там же. Я просто привязываю его для упрощения перекрестных ссылок. –