【问题标题】:Proc::Daemon with mod_perl does not write STDOUT or STDERR带有 mod_perl 的 Proc::Daemon 不会写入 STDOUT 或 STDERR
【发布时间】:2017-01-15 19:23:32
【问题描述】:

因此,我在 mod_perl 脚本中使用 Proc::Daemon:

$bindir, $ddir 是可执行文件/日志文件的位置,$jid 是每个进程的唯一标识符(以避免多个进程打开同一个文件)。 $cmd 加载了任意 perl 脚本和参数。

   my $daemon = Proc::Daemon->new (
            work_dir        => $bindir,
            child_STDOUT    => $ddir.'/'.$jid.'_stdout.log',
            child_STDERR    => $ddir.'/'.$jid.'_stderr.log',
            pid_file        => $ddir.'/'.$jid.'_pid.txt',
            exec_command => $cmd,
    );

    my $pid = $daemon->Init();

在将 Apache 与 cgi-script(无 mod_perl)一起使用时,上述内容可以正常工作。在“$cmd”进程中,打印STDERR日志并将其打印到上面定义的日志文件中。

当我在 Ubuntu Linux 14.04 LTS 上使用 Apache2 使用 mod_perl2 运行上述程序时,使用 PID 写入 pid 文件并创建上述日志文件,但没有任何内容写入日志文件。我可以在 $cmd 中打开新的文件描述符并写入它们,但在 mod_perl 下,它不会将输出发送到 child_STDOUT 和 child_STDERR 文件。

我认为我遗漏了一些非常明显的东西。有没有其他人以前见过这个,或者有任何建议让它在 mod_perl 中工作。

附加信息 在 Apache 中使用 mpm_prefork 模块

相关的 Apache 配置

    <Files "*.pl">
            # SetHandler cgi-script # It works if I use cgi-script
            SetHandler perl-script
            PerlOptions -SetupEnv # Tried with and without this
            # PerlHandler ModPerl::RegistryPrefork # Using this made no difference
            PerlHandler ModPerl::Registry

    </Files>

【问题讨论】:

  • 它可能假设 fileno(STDOUT) 是 2(等等),但它不是,或者过于特殊。
  • 我认为这是一个很好的假设,但它在 Proc::Daemon 页面中说,第二个孩子关闭所有打开的文件描述符(除非您定义 dont_close_fh 和/或 dont_close_fd)。第二个孩子打开 STDIN、STDOUT 和 STDERR 到构造函数中定义的位置(新)。所以它应该关闭所有文件描述符,然后打开新的。也许 mod_perl 以某种方式改变了 STDIN/STDOUT 的全局常量??
  • 我不会认为这与我所说的相矛盾,尤其是因为它是根据 STDOUT 而不是 fd 2 说话的。
  • 是的,不一定是矛盾的,更多附加信息。有趣的是 Proc::Daemon 应该关闭子进程中的所有文件句柄,然后打开新的文件句柄,这意味着它不应该关心 STDIN/OUT 是否为 0/1 它应该只关闭它们,然后打开新的。有趣的附加说明,如果我使用 SetHandler modperl 而不是 SetHandler perl-script,在子进程中打印和打印 STDERR 会转到指定的日志文件,但随后在常规的非分叉脚本中打印不再连接到浏览器。跨度>
  • 两者之间的区别之一是 perl-script 执行以下操作:STDIN 和 STDOUT 绑定到请求对象 $r,这使得从 STDIN 读取并通过 CORE 直接打印到 STDOUT 成为可能::print(),而不是像 $r->puts() 这样的隐式调用。所以我想问题是,我如何为子进程解开这些,但将配置留给父进程?我可能会自己动手卷叉,但我宁愿不这样做,我喜欢 Proc::Daemon 的整体易用性。

标签: linux perl apache2 mod-perl2 mod-perl-registry


【解决方案1】:

好的,所以有很多解决方案都不起作用这就是我最终要做的。我创建了一个名为 launchjob.pl 的脚本:

#!/usr/bin/perl -w

use strict;
use warnings;

use POSIX 'setsid';
use Proc::Daemon;

my $bindir = $ARGV[0];
my $ddir = $ARGV[1];
my $jid = $ARGV[2];
my $cmd = $ARGV[3];

setsid or die "Cannot start a new session: $!";

my $daemon = Proc::Daemon->new (
                work_dir        => $bindir,
                child_STDOUT    => $ddir.'/'.$jid.'_stdout.log',
                child_STDERR    => $ddir.'/'.$jid.'_stderr.log',
                pid_file        => $ddir.'/'.$jid.'_pid.txt',
                exec_command => $cmd,
             );

my $pid = $daemon->Init();

exit 1;

我用以下代码替换了主线中调用 Proc::Daemon 的代码:

以下操作无效。 Proc::Daemon 给了我一个 sh: No such file or directory 错误。

system('launchjob.pl', $bindir, $ddir, $jid, $cmd);

相反,我使用了以下似乎按预期运行。

使用 IPC::Run3; run3("launchjob.pl ".$bindir." ".$ddir." ".$jid." ".$cmd);

这似乎已经解决了。

【讨论】:

    猜你喜欢
    • 2013-10-20
    • 1970-01-01
    • 2016-11-03
    • 2019-08-21
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 2019-12-11
    相关资源
    最近更新 更多