luoxiaojun1992 / sw-fw-less-app

Swoole Http Server App

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

swoole_process::kill 无法结束进程是什么原因?

xkungfu opened this issue · comments

start.php 文件内调用swoole_process::kill((int) $pid);

执行结果返回true.
但是通过swoole_process::kill($pid, 0)检查进程仍然存在。

应该可以排除环境和版本原因,因为单独写了一个测试的swoole的启动文件。\Swoole\Process::kill可以结束进程。

那么,sw-fw-less-app启动的swoole进程有什么特别之处,以致让swoole_process::kill无法结束进程呢?

可能是什么原因?

谢谢!

请问start.php文件什么位置调用swoole_process::kill代码?pid是从什么地方获取的呢?是否能提供完整可复现的代码

swoole_process::kill,执行后,进程还在。但是已经不接收信号 了,客户端的请求已经不执行了。命令行查看进程状态,显示多个CLOSE_WAIT 状态的进程。然后再启动swfwless也是启动不了,显示端口占用中。

代码如下:


$server_daemonize = 0;
//启动后存储pid到文件:
$pid_file = __DIR__ . '/server.pid';
//echo "\n ++ pid_file: " . $pid_file;

//获取命令行执行参数:
$shortopts = "s:"; // Required value
$options = getopt($shortopts);
//var_dump($options);

$opt = $options['s'] ?? 'null'; //echo "\n ++ opt: " . $opt;

if ($opt == 'k') {

	echo "++try stopping! \n";

	if (file_exists($pid_file)) {

		$pid = file_get_contents($pid_file);
		echo "swserver_stop pid: ", var_dump($pid);

		//swserver_stop((int) $pid);
		\Swoole\Process::kill((int) $pid);

		$time = time();
		$flag = false;
		while (true) {
			//每隔500毫秒检查一次:
			usleep(500000);
			if (!\Swoole\Process::kill($pid, 0)) {
				echo "\n server stop at " . date("y-m-d h:i:s") . "\n";
				//删除pid文件:
				if (is_file($pid_file)) {
					unlink($pid_file);
				}
				break;
			} else {
				//等待3秒
				if (time() - $time > 3) {
					echo "stop server fail. try again \n";
					echo "netstat -apn | grep 9876 \n";
					break;
				}
			}
		}

		exit;

	} else {
		echo "PID file not exists! \n netstat -apn | grep 9876 \n";
	}

	exit;

}

if ($opt == 'd') {
	$server_daemonize = 1;
}

if ($opt == 'r') {
	echo "\n ++reload!";
	exit;
}

echo "start... \n";

!defined('APP_BASE_PATH') && define('APP_BASE_PATH', __DIR__ . '/');
//echo "APP_BASE_PATH: " . APP_BASE_PATH . "\n";

if (extension_loaded('jsonnet')) {
	!defined('CONFIG_FORMAT') && define('CONFIG_FORMAT', 'array,jsonnet');
}

require_once __DIR__ . '/vendor/autoload.php';

echo "\n ++ server_daemonize: " . $server_daemonize . PHP_EOL;

//This app supports hot reload and shutdown triggered by SIGTERM
$server = new \SwFwLess\bootstrap\App($server_daemonize, $pid_file);
$server->run();

App.php文件的修改:


    public function __construct($server_daemonize, $pid_file)
    {
        $this->bootstrap();

        $this->swHttpServer = new \Swoole\Http\Server(
            config('server.host'),
            config('server.port')
        );

        $serverConfig = [
            'reactor_num' => config('server.reactor_num'),
            'worker_num' => config('server.worker_num'),
            'daemonize' => $server_daemonize,
            'backlog' => config('server.backlog'),
            'max_request' => config('server.max_request'),
            'dispatch_mode' => config('server.dispatch_mode'),
            'open_http2_protocol' => config('server.open_http2_protocol'),
            'task_worker_num' => config('server.task_worker_num'),
            'task_enable_coroutine' => config('server.task_enable_coroutine'),
            'pid_file' => $pid_file
        ];

命令行执行swfwless启动文件start.php时,在后面加上“ -sk”传入参数。

另外,直接在命令行输入 kill -15 进程号,也无法结束swfwless进程。swoole_process::kill调用的命令可能就是kill -15

独立的用于测试启动swoole和关闭进程的代码,存储为PHP文件即可执行:


<?php

$shortopts = "";
$shortopts .= "s:"; // Required value
//$shortopts .= "d:"; // Optional value
$options = getopt($shortopts);
//var_dump($options);

$arg = $options['s'] ?? 'null';

(new SwooleTest())->handle(array('action' => $arg));

class SwooleTest {
	private $server;

	private $pid_file;
	/**
	 * The name and signature of the console command.
	 *
	 * @var string
	 */
	protected $signature = 'swoole {action}';

	/**
	 * The console command description.
	 *
	 * @var string
	 */
	protected $description = 'start or stop the swoole process';

	/**
	 * Create a new command instance.
	 *
	 * @return void
	 */
	public function __construct() {
		$this->pid_file = __DIR__ . '/swoole_test.pid';
		echo "this pid_file: " . $this->pid_file . "\n";
	}

	/**
	 * Execute the console command.
	 *
	 * @return mixed
	 */
	public function handle($args = array('action' => 'start')) {
		//获取传递的操作
		$arg = $args['action'];

		switch ($arg) {
		case 'start':
			//检测进程是否已开启
			$pid = $this->getPid();
			if ($pid && \Swoole\Process::kill($pid, 0)) {
				echo "process already exist!\r\n";
				exit;
			}

			$this->server = new \swoole_http_server("0.0.0.0", 9876);
			$this->server->set([
				'worker_num' => 8,
				'daemonize' => 1,
				'max_request' => 1000,
				'dispatch_mode' => 2,
				'pid_file' => $this->pid_file,
			]);

			//绑定操作类回调函数
			//$app = App::make('App\Handles\SwooleWebSocketHandle');
			//$app = AppTest::testcallback();
			
			$callback = function() {
				return 'starting...';
			};

			//$this->server->on('open', array($app, 'onOpen'));

			$this->server->on('message', $callback);
			$this->server->on('request', $callback);

			//$this->server->on('close', array($app, 'onClose'));

			echo "process created successful!\r\n";

			$this->server->start();
			break;

		case 'stop':
			$pid = $this->getPid();
			//$pid = 14319;
			if (!$pid) {
				echo "process not started!\r\n";
				exit;
			}
			if (\Swoole\Process::kill((int) $pid)) {
				echo "process close successful!\r\n";
				exit;
			}

			echo "process close failed!\r\n";
			break;

		default:
			echo "operation method does not exist!\r\n";
		}

	}

	//获取pid
	private function getPid() {
		return file_exists($this->pid_file) ? file_get_contents($this->pid_file) : false;
	}
}

class AppTest {

	public function testcallback($value = '') {
		return 'starting...';
	}

}

可能是这块代码的问题,已经尝试修复,请更新composer包之后再试试

$this->hotReload();
$this->registerScheduler();
$this->pullApolloConfig();

haode.谢谢

现在正常了,可以通过上面的代码实现结束进程了。非常感谢!

不客气