swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.44k stars 3.16k forks source link

[bug]在定时器中创建子程序会直接变成僵尸 #2162

Closed fanybook closed 5 years ago

fanybook commented 5 years ago

timer 本身是个子进程,托管在manager下。 看官方文档,好像说 start会清除父进程的 timer,但是我这个timer可以一直打印log,但是孙进程创建出来就是僵尸(它的父进程是这个timer进程,而timer进程没死)

说明:创建孙进程时无报错,成功返回pid。孙进程里的 exec 不会有错,跟它没关,写什么都这样。

<?php

namespace Pkg\Swoola\Components\Swoole\Process;

trait QueueWorkerTrait
{
    protected $queueWorkerPids = [];

    public function addQueueWorker()
    {
        $self = $this;
        $process = new \Swoole\Process(function(\Swoole\Process $worker) {
            \Pkg\Swoola\set_process_name('swoola - timer process ');
            \Swoole\Process::signal(SIGCHLD, function($sig) {
                // 必须为false,非阻塞模式
                while($ret = \Swoole\Process::wait(false)) {
                    echo "PID={$ret['pid']}\n";
                }
            });

            swoole_timer_tick(1000, function() {
                if (!$this->queueWorkerPids) {
                    $this->createQueueWorker();
                } else {
                    foreach ($this->queueWorkerPids as $idx => $pid) {
                        $current_time = date('H:i:s');
                        if (\Swoole\Process::kill($pid, 0)) {
                            echo "PID[{$pid}] is alived({$current_time}).\n";
                        } else {
                            echo "PID[{$pid}] is died.\n";
                            unset($this->queueWorkerPids[$idx]);
                            $this->createQueueWorker($idx);
                        }
                    }
                }
            });
        });

        $this->server->addProcess($process);
        // $process->start();
    }

    protected function createQueueWorker($idx = null)
    {
        $num = is_null($idx) ? 2 : 1;

        for ($i = 0; $i < $num; $i++) {
            $process = new \Swoole\Process(function(\Swoole\Process $worker) use($i, $idx) {
                $worker->exec(PHP_BINARY, [SWOOLA_APP_DIR.'/artisan', 'queue:work']);
            });

            $pid = $process->start();
            if (is_null($idx)) {
                $this->queueWorkerPids[$i] = $pid;
            } else {
                $this->queueWorkerPids[$idx] = $pid;
            }

            // if ($pid) {

            // } else {
            //     $errno = swoole_errno();
            //     var_dump(swoole_strerror($errno));
            // }
        }
    }
}
fanybook commented 5 years ago
            // swoole_timer_tick(1000, function() {
            while (true) {
                if (!$this->queueWorkerPids) {
                    $this->createQueueWorker();
                } else {
                    foreach ($this->queueWorkerPids as $idx => $pid) {
                        $current_time = date('H:i:s');
                        if (\Swoole\Process::kill($pid, 0)) {
                            echo "PID[{$pid}] is alived({$current_time}).\n";
                        } else {
                            echo "PID[{$pid}] is died.\n";
                            unset($this->queueWorkerPids[$idx]);
                            $this->createQueueWorker($idx);
                        }
                    }
                }

                sleep(1);
            }
            // });

改成死循环,创建的孙程序就没问题

            swoole_timer_tick(1000, function() {
                echo '2333333';
            });

            // swoole_timer_tick(1000, function() {
            while (true) {
                if (!$this->queueWorkerPids) {
                    $this->createQueueWorker();
                } else {
                    foreach ($this->queueWorkerPids as $idx => $pid) {
                        $current_time = date('H:i:s');
                        if (\Swoole\Process::kill($pid, 0)) {
                            echo "PID[{$pid}] is alived({$current_time}).\n";
                        } else {
                            echo "PID[{$pid}] is died.\n";
                            unset($this->queueWorkerPids[$idx]);
                            $this->createQueueWorker($idx);
                        }
                    }
                }

                sleep(1);
            }
            // });

在死循环外,加timer,创建出孙程序也变成僵尸

matyhtf commented 5 years ago

请使用协程模式

<?php
go(function() {
    while(1)
    {
        co::sleep(1);
        var_dump(co::exec("ps aux"));
    }
});

swoole_event_wait();
fanybook commented 5 years ago

懂了 👍