为了执行一些 JavaScript 单元测试业力在 docker 容器内(基于 ubuntu 14.04),我在容器中使用业力脚本启动器和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 会终止生成的浏览器实例 - 在我的例子中,是通过 xvfb-run 启动 Firefox 的脚本。
在上面的脚本中,您可以看到我注册了一个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
尽管 bug 的状态早在 2012 年就被修复了,但它似乎仍然有效。
是否有任何礼貌的方式来终止该xvfb-run
进程,以便正确清理其他进程?
我已经在 Stack Overflow 上问过这个问题,但到目前为止还没有得到答案。也许对于 Stack Overflow 来说有点 OT,但这里位置更好?!
答案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 测试运行程序的例子中,一旦 Karma 关闭了 firefox 实例,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
我的解决方案是在 Docker 入口点脚本中启动 xvfb:
Xvfb :0 -screen 0 1024x768x24 &
.bashrc
如果您不使用 Docker,您也可以将同一行放入某种操作系统启动脚本(例如)脚本中。
然后在另一个脚本中,我导出显示并调用我想要使用的实际函数
export DISPLAY=:0
firefox $1