将子进程与父进程断绝关系

将子进程与父进程断绝关系

如果$PID_PARENT启动了$PID_CHILD,我怎样才能分离(disown?) ,$PID_CHILD以便$PID_PARENT当我杀死时$PID_PARENT$PID_CHILD继续运行就像什么都没发生一样?

具体来说, my$PID_PARENT是正在运行的进程Jenkins(或Java运行运行 Jenkins 的服务器的进程),并且$PID_CHILD真的很长我不想在重新启动 Jenkins 后重新启动作业(这是一些维护所需要的)。本质上,我想停止 Jenkins,但不想停止它开始的长期工作,而且我知道两个 PID。

更新1:我从登录 shell 中发现disown并尝试过(所以不是父 PID shell):

disown $PID_CHILD

但得到了

-bash: disown: 13924: no such job

正确$PID_CHILD和做的事

ps -o ppid= $PID_CHILD

回报$PID_PARENT

更新2:根据@Rui 的回答,我在 Jenkins 中做了一个临时 hack 工作,这次只从父 shell 运行:

disown 13924 

但仍然得到了

disown: 13924: no such job

答案1

一种方法是让子进程与父进程解除关联。这会在子进程中需要合适的代码,或在执行实际代码之前执行解除关联的包装脚本:

#!/usr/bin/env perl
use strict;
use warnings;
die "Usage: $0 command [args ..]\n" unless @ARGV;
# diassociate this process (some folks also do a double-fork thing)
use POSIX "setsid";
chdir("/") || die "can't chdir to /: $!";
open( STDIN,  "< /dev/null" ) || die "can't read /dev/null: $!";
open( STDOUT, "> /dev/null" ) || die "can't write to /dev/null: $!";
defined( my $pid = fork() ) || die "can't fork: $!";
exit if $pid;    # non-zero now means I am the parent
( setsid() != -1 ) || die "Can't start a new session: $!";
open( STDERR, ">&STDOUT" ) || die "can't dup stdout: $!";
# and replace ourself with whatever we were called with
exec @ARGV;

如果保存为solitary可以通过以下方式进行测试:

% ./solitary logger greppable
% grep greppable /var/log/system.log
Jun 27 10:52:15 hostn jhqdoe[20966]: greppable
% 

因为logger(1)标准文件句柄作为解除关联的一部分已全部关闭。这些可能需要重定向到您的应用程序的其他地方。

请注意,如果 Jenkins(或 systemd 或其他)使用 PID 命名空间,则该进程无论如何分叉都无法逃脱,这可能是不可能的,在这种情况下,您将需要一些容器级解决方案,或者重新审视您正在做的事情试图做。

答案2

我认为你应该能够简单地做

$ disown $PID

然后,如果您终止 shell 会话,该进程仍将运行。

答案3

您需要disown从调用该进程的 shell 中执行操作。因此,从其他 shell 调用您会收到消息no such job

要真正否认进程并告诉它忽略挂断信号,您可以从调用该进程的 shell 执行以下操作:

disown -h $PID

来自 disown 帮助:

$ disown --help disown: disown [-h] [-ar] [工作规范 ... | pid ...]
从当前 shell 中删除作业。

    Removes each JOBSPEC argument from the table of active jobs.  Without
    any JOBSPECs, the shell uses its notion of the current job.

    Options:
      -a    remove all jobs if JOBSPEC is not supplied
      -h    mark each JOBSPEC so that SIGHUP is not sent to the job if the
                    shell receives a SIGHUP
      -r    remove only running jobs

    Exit Status:
    Returns success unless an invalid option or JOBSPEC is given.

答案4

当创建一个在 Jenkins 构建完成后仍然存在的后台进程时,您需要注意Jenkins 进程树杀手。当构建退出时,进程树杀手会尝试终止与该构建相关的所有进程,即使这些进程已不再属于构建进程并且不再是构建进程的子进程。

上面的链接中有关于如何禁用特定作业或整个 Jenkins 的进程树杀手的说明。

相关内容