引入其他框架时,由于resetstd导致std写入异常,求老大更新

liruizhe1

问题描述

引入laravel时,发现用debug模式启动正常,用demon模式启动则出现异常。
经过排查发现laravel在命令行启动时,保存了stdout的handle
当workerman以demon模式启动时,会关闭stdout的handle,并重定向到文件中。

程序代码或配置

    /**
     * Redirect standard input and output.
     *
     * @param bool $throwException
     * @return void
     * @throws Exception
     */
    public static function resetStd(bool $throwException = true): void
    {
        if (!static::$daemonize || DIRECTORY_SEPARATOR !== '/' || static::$hasResetStd) {
            return;
        }
        global $STDOUT, $STDERR;
        $handle = fopen(static::$stdoutFile, "a");
        if ($handle) {
            unset($handle);
            set_error_handler(function () {
            });
            if ($STDOUT) {
                fclose($STDOUT);
            }
            if ($STDERR) {
                fclose($STDERR);
            }
            if (is_resource(STDOUT)) {
                fclose(STDOUT);
            }
            if (is_resource(STDERR)) {
                fclose(STDERR);
            }
            $STDOUT = fopen(static::$stdoutFile, "a");
            $STDERR = fopen(static::$stdoutFile, "a");
            // Fix standard output cannot redirect of PHP 8.1.8's bug
            if (function_exists('posix_isatty') && posix_isatty(2)) {
                ob_start(function ($string) {
                    file_put_contents(static::$stdoutFile, $string, FILE_APPEND);
                }, 1);
            }
            // change output stream
            static::$outputStream = null;
            static::outputStream($STDOUT);
            restore_error_handler();

            //mark as reset
            static::$hasResetStd = true;

            return;
        }
        if ($throwException) {
            throw new RuntimeException('Can not open stdoutFile ' . static::$stdoutFile);
        }
    }

解决方案

增加一个开关,
如果有需要,在任何程序启动前,完成std的重定向。然后在workerman启动时不再重置
已经提交PR,请老大审阅
https://github.com/walkor/workerman/pull/924

774 1 0
1个回答

walkor 打赏

如果不关闭STDOUT,终端关闭后打印数据可能会导致进程退出。

  • liruizhe1 2023-06-29

    会关闭STDOUT,只不过增加一个开关判断,如果已经关闭过就不再关闭一次。这样我可以在程序开始的时候就先手动调用resetStd(), 完成stdout重定向。后续 worker::startAll()的时候就不会再次关闭了。

  • walkor 2023-06-29

    直接用 Worker::$daemonize 控制吧。
    workerman作为底层不会随意添加属性或者方法,除非是十分必要。

  • liruizhe1 2023-06-30

    明白,如果添加功能很谨慎,是否可以考虑将 worker 类的一些方法改为public呢?比如worker::startAll()里面的方法,这样可以自己控制其中的顺序。
    或者增加marco功能实现,方便扩展功能来实现自定义。
    直接关闭STDOUT对其他框架侵入很大,尤其是Symfony\Component\Console 库,大量依赖了STDOUT的句柄实例,任何修复和兼容方式都是很不友好的硬编码,除非能控制是否关闭STDOUT

年代过于久远,无法发表回答
×
🔝