如何使用 mod_perl2 正确分叉?

发布于 2024-07-13 04:21:25 字数 1260 浏览 7 评论 0原文

我在从 mod_perl2 下运行的某些代码中分叉长时间运行的进程时遇到问题。

大部分情况下一切正常,但似乎分叉进程持有 Apache 日志文件的打开句柄 - 这意味着 Apache 在进程运行时不会重新启动(我收到“无法打开日志文件”消息)。

这是我正在使用的代码:

use POSIX; # required for setsid

# Do not wait for child processes to complete
$SIG{CHLD} = 'IGNORE';

# fork (and make sure we did!)
defined (my $kid = fork) or die "Cannot fork: $!\n";

if ($kid) {
    return (1, $kid);
}else {
    # chdir to /, stops the process from preventing an unmount
    chdir '/' or die "Can't chdir to /: $!";

    # dump our STDIN and STDOUT handles
    open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
    open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";

    # redirect for logging
    open STDERR, '>', $log_filename or die "Can't write to log: $!";

    # Prevent locking to apache process
    setsid or die "Can't start a new session: $!";

    # execute the command
    exec( $cmd, @args );

    die "Failed to exec";
}

早在 mod_perl1 时代,我记得使用 $r->cleanup_for_exec 来解决这个问题,但 mod_perl2 似乎不支持它。 (编辑:显然不再需要了.. )

任何有关如何从 mod_perl2 正确启动长时间运行的进程而不出现这些问题的建议将不胜感激!

I'm having trouble forking a long-running process from some code running under mod_perl2.

Everything works for the most part, but it seems that the forked process is holding open handles to Apache's logfiles - this means Apache won't restart while the process is running (I get a 'failed to open logfiles' message).

Here's the code I'm using:

use POSIX; # required for setsid

# Do not wait for child processes to complete
$SIG{CHLD} = 'IGNORE';

# fork (and make sure we did!)
defined (my $kid = fork) or die "Cannot fork: $!\n";

if ($kid) {
    return (1, $kid);
}else {
    # chdir to /, stops the process from preventing an unmount
    chdir '/' or die "Can't chdir to /: $!";

    # dump our STDIN and STDOUT handles
    open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
    open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!";

    # redirect for logging
    open STDERR, '>', $log_filename or die "Can't write to log: $!";

    # Prevent locking to apache process
    setsid or die "Can't start a new session: $!";

    # execute the command
    exec( $cmd, @args );

    die "Failed to exec";
}

Back in the mod_perl1 days, I recall using $r->cleanup_for_exec to solve this problem, but it doesn't seem to be supported under mod_perl2. (Edit: Apparently it's not required any more..)

Any advice on how to correctly start a long-running process from mod_perl2 without these problems would be greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷途知返 2024-07-20 04:21:25

您可能想阅读 这个讨论。 看来你不应该 fork mod_perl 除非你知道如何准备东西。 您必须使用诸如 Apache2::SubProcess 之类的模块

You probably want to read this discussion. It seems you shouldn't fork on mod_perl unless you know how to prepare things. You have to use a module such as Apache2::SubProcess

青春有你 2024-07-20 04:21:25

尝试在叉子之前关闭 STDIN/STDOUT 手柄。

Try closing your STDIN/STDOUT handles before the fork.

飘逸的'云 2024-07-20 04:21:25

在我的(以前的mod_perl,现在的FCGI)代码中,我在“if($kpid)”的“else”子句中,

    close STDIN;
    close STDOUT;
    close STDERR;
    setsid();

另外,由于我忘记的原因,我立即再次分叉,然后在中< /em> 子进程重新打开 STDIN、STDOUT 和 STDERR。

所以它看起来像:

$SIG{CHLD} = 'IGNORE';

# This should flush stdout.
my $ofh = select(STDOUT);$| = 1;select $ofh;

my $kpid = fork;
if ($kpid)
{
    # Parent process
    waitpid($kpid, 0);
}
else
{
    close STDIN;
    close STDOUT;
    close STDERR;
    setsid();
    my $gpid = fork;
    if (!$gpid)
    {
        open(STDIN, "</dev/null") ;#or print DEBUG2 "can't redirect stdin\n";
        open(STDOUT, ">/dev/null") ;#or print DEBUG2 "can't redirect stdout\n";
        open(STDERR, ">/dev/null") ;#or print DEBUG2 "can't redirect stderr\n";
        # Child process
        exec($pgm, @execargs) ;# or print DEBUG2 "exec failed\n";
    }
    exit 0;
}

In my (formerly mod_perl, now FCGI) code, I have in the "else" clause of the "if ($kpid)",

    close STDIN;
    close STDOUT;
    close STDERR;
    setsid();

Also, for reasons that I forgot, I immediately fork again, and then in that child re-open STDIN, STDOUT, and STDERR.

So it looks like:

$SIG{CHLD} = 'IGNORE';

# This should flush stdout.
my $ofh = select(STDOUT);$| = 1;select $ofh;

my $kpid = fork;
if ($kpid)
{
    # Parent process
    waitpid($kpid, 0);
}
else
{
    close STDIN;
    close STDOUT;
    close STDERR;
    setsid();
    my $gpid = fork;
    if (!$gpid)
    {
        open(STDIN, "</dev/null") ;#or print DEBUG2 "can't redirect stdin\n";
        open(STDOUT, ">/dev/null") ;#or print DEBUG2 "can't redirect stdout\n";
        open(STDERR, ">/dev/null") ;#or print DEBUG2 "can't redirect stderr\n";
        # Child process
        exec($pgm, @execargs) ;# or print DEBUG2 "exec failed\n";
    }
    exit 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文