编辑

编辑

为了执行一些 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

相关内容