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

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

Для того чтобы выполнить некоторые модульные тесты JavaScript скармавнутри контейнера Docker (на основе Ubuntu 14.04) Я запускаю Firefox в контейнере с помощьюкарма-скрипт-лаунчерс xvfb-run. Стартовый скрипт выглядит так:

#!/bin/bash
set -o errexit 

# nasty workaround as xvfb-run doesn't cleanup properly...
trap "pkill -f /usr/lib/firefox/firefox" EXIT

xvfb-run --auto-servernum --server-args='-screen 0, 1024x768x16' firefox $1

Запуск браузера и выполнение юнит-тестов работает очень хорошо. После выполнения тестов karma завершает порожденный экземпляр браузера - в моем случае скрипт, который запускал firefox через xvfb-run.

В приведенном выше скрипте вы можете видеть, что я зарегистрировал a trapдля завершения запущенного firefox при выходе из моего скрипта. Это работает, но скрипт не очень хороший гражданин, так как он завершаетвсеэкземпляры Firefox, которые в данный момент запущены, вместо того, чтобы просто завершить один экземпляр, запущенный скриптом. Сначала я попытался убить процесс, xfvb-runно убийство этого процесса не оказало никакого влияния на подпроцесс, запущенный xvfb-runскриптом...

Если я вручную запущу Firefox, то xvfb-runпоявится куча запущенных процессов:

root@1d7a5988e521:/data# xvfb-run --auto-servernum --server-args='-screen 0, 1024x768x16' firefox &
[1] 348
root@1d7a5988e521:/data# ps ax
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 bash
  348 ?        S      0:00 /bin/sh /usr/bin/xvfb-run --auto-servernum --server-args=-screen 0, 1024x768x16 firefox
  360 ?        S      0:00 Xvfb :99 -screen 0, 1024x768x16 -nolisten tcp -auth /tmp/xvfb-run.bgMEuq/Xauthority
  361 ?        Sl     0:00 /usr/lib/firefox/firefox
  378 ?        S      0:00 dbus-launch --autolaunch bcf665e095759bae9fc1929b57455cad --binary-syntax --close-stderr
  379 ?        Ss     0:00 //bin/dbus-daemon --fork --print-pid 5 --print-address 7 --session
  388 ?        S      0:00 /usr/lib/x86_64-linux-gnu/gconf/gconfd-2
  414 ?        R+     0:00 ps ax
root@1d7a5988e521:/data#

Если я сейчас убью xvfb-runпроцесс (PID 348), то только этот процесс будет завершен, а остальные процессы останутся запущенными. Если я вместо этого убью процесс Firefox (PID 361), скрипт xvfb-runправильно завершит работу и удалит также другие процессы. Но из моего скрипта я знаю только PID процесса xvfb-run...

Во время моего исследования я наткнулся наэтот довольно старый отчет об ошибкечто xvfb-run, похоже, все еще актуально, несмотря на то, что ошибка была исправлена ​​еще в 2012 году.

Есть ли какой-либо вежливый способ завершить xvfb-runпроцесс, чтобы другие процессы были правильно очищены?


Я уже спрашивал об этом на Stack Overflow, но до сих пор не получил ответа. Возможно, это немного OT для Stack Overflow, но лучше разместить здесь?!

решение1

Похоже, вы используете его только xvfb-runиз-за --auto-servernumфункциональности.

Как отметил @meuh: эта логикана самом деле довольно просто:

# Copyright (C) 2005 The T2 SDE Project
# Copyright (C) XXXX - 2005 Debian
# GNU GPLv2
find_free_servernum() {
    # Sadly, the "local" keyword is not POSIX.  Leave the next line commented in
    # the hope Debian Policy eventually changes to allow it in /bin/sh scripts
    # anyway.
    #local i

    i=$SERVERNUM
    while [ -f /tmp/.X$i-lock ]; do
        i=$(($i + 1))
    done
    echo $i
}

Определив эту функцию: вы можете попробовать такой вызовВместо того, чтобы использоватьxvfb-run:

Xvfb :$(find_free_servernum) -screen 0, 1024x768x16 firefox $1 &
THE_PID=$!
# kill Xvfb whenever you feel like it
kill -15 $THE_PID

С xvfb-runудалением: нам больше не нужно беспокоиться о том, как убить xvfb-run.

решение2

Я сегодня столкнулся с этой самой проблемой.

ВсеXсерверподдержите -terminateаргумент.

−завершить

заставляет сервер завершить работу при сбросе сервера, вместо продолжения работы. Это переопределяет предыдущую опцию командной строки −noreset.

Поэтому я в конечном итоге указал это с помощью xvfb-run's -s:

xvfb-run -d -s '-terminate' firefox --no-remote --profile $PROFILE_DIR $URL

Таким образом, в нашем случае с программой запуска тестов Karma, как только экземпляр Firefox закрывается программой Karma, сервер Xvfb завершает работу, поскольку завершается его последний xclient (Firefox). xvfb-run завершает выполнение после того, как Firefox также завершает работу.

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

В итоге я собрал свою собственную «более простую» версию скрипта xvfb-run:


PROFILE=$(mktemp -d)
trap "rm -rf $PROFILE" EXIT

# Start Xvfb and let it find a display number itself.
# Some versions of Xvfb (apparently 1.17.x) refuse to write to stdout
Xvfb -displayfd 4 -terminate -nolisten tcp 4>$PROFILE/.Xdisplay &

# Wait a few seconds for Xvfb to start
sleep ${START_WAIT-2}

${FIREFOX_HOME}/firefox --profile $PROFILE --no-remote --display :$(<$PROFILE/.Xdisplay) "${@?}" &
# Karma appears to send a SIGTERM to the browser when it's done, forward that signal to the Firefox process.
trap "kill -SIGTERM $!" SIGTERM

# Wait for all children to terminate
wait

решение3

Моим решением было запустить xvfb в скрипте точки входа Docker:

Xvfb :0 -screen 0 1024x768x24 &

Эту же строку можно поместить в какой-либо скрипт запуска ОС (например .bashrc, ), если вы не используете Docker.

Затем в другом скрипте я экспортировал отображение и вызвал нужную мне функцию.

export DISPLAY=:0
firefox $1

Связанный контент