eee
This commit is contained in:
@@ -31,9 +31,13 @@ class State extends Component
|
||||
*/
|
||||
public function isRunner(): bool
|
||||
{
|
||||
if ($this->getPidFilePid() !== null || $this->getNamedServerPids() !== []) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$ports = $this->sortService($this->servers);
|
||||
foreach ($ports as $config) {
|
||||
if (checkPortIsAlready($config['port'])) {
|
||||
if (checkPortIsAlready($config->port)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -47,13 +51,161 @@ class State extends Component
|
||||
*/
|
||||
public function exit($port): void
|
||||
{
|
||||
if (!($pid = checkPortIsAlready($port))) {
|
||||
$pids = $this->collectStopPids((int)$port);
|
||||
if ($pids === []) {
|
||||
return;
|
||||
}
|
||||
while (checkPortIsAlready($port)) {
|
||||
Process::kill($pid, 0) && Process::kill($pid, SIGTERM);
|
||||
usleep(300);
|
||||
|
||||
$this->terminatePids($pids, SIGTERM, 30);
|
||||
|
||||
$remaining = array_values(array_filter($pids, [$this, 'isProcessAlive']));
|
||||
if ($remaining !== []) {
|
||||
$this->terminatePids($remaining, SIGKILL, 10);
|
||||
}
|
||||
|
||||
if (!checkPortIsAlready((int)$port)) {
|
||||
@unlink(storage('.swoole.pid'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function collectStopPids(int $port): array
|
||||
{
|
||||
$pids = [];
|
||||
|
||||
$pidFilePid = $this->getPidFilePid();
|
||||
if ($pidFilePid !== null) {
|
||||
$pids[] = $pidFilePid;
|
||||
$pids = array_merge($pids, $this->getDescendantPids($pidFilePid));
|
||||
}
|
||||
|
||||
$pids = array_merge($pids, $this->getNamedServerPids());
|
||||
|
||||
$portPid = checkPortIsAlready($port);
|
||||
if ($portPid !== false) {
|
||||
$pids[] = (int)$portPid;
|
||||
$pids = array_merge($pids, $this->getDescendantPids((int)$portPid));
|
||||
}
|
||||
|
||||
$currentPid = getmypid();
|
||||
$pids = array_values(array_unique(array_filter(array_map('intval', $pids), function (int $pid) use ($currentPid) {
|
||||
return $pid > 1 && $pid !== $currentPid;
|
||||
})));
|
||||
rsort($pids);
|
||||
|
||||
return $pids;
|
||||
}
|
||||
|
||||
|
||||
private function terminatePids(array $pids, int $signal, int $rounds): void
|
||||
{
|
||||
for ($i = 0; $i < $rounds; $i++) {
|
||||
$alive = false;
|
||||
foreach ($pids as $pid) {
|
||||
if (!$this->isProcessAlive($pid)) {
|
||||
continue;
|
||||
}
|
||||
$alive = true;
|
||||
@Process::kill($pid, $signal);
|
||||
}
|
||||
|
||||
if (!$alive) {
|
||||
return;
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function getPidFilePid(): ?int
|
||||
{
|
||||
$pidFile = storage('.swoole.pid');
|
||||
if (!is_file($pidFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$pid = (int)trim((string)file_get_contents($pidFile));
|
||||
if ($pid <= 1 || !$this->isProcessAlive($pid)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $pid;
|
||||
}
|
||||
|
||||
|
||||
private function getDescendantPids(int $parentPid): array
|
||||
{
|
||||
$processes = $this->listProcesses();
|
||||
$children = [];
|
||||
foreach ($processes as $process) {
|
||||
$children[(int)$process['ppid']][] = (int)$process['pid'];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
$stack = [$parentPid];
|
||||
while ($stack !== []) {
|
||||
$pid = array_pop($stack);
|
||||
foreach ($children[$pid] ?? [] as $childPid) {
|
||||
$result[] = $childPid;
|
||||
$stack[] = $childPid;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
private function getNamedServerPids(): array
|
||||
{
|
||||
$siteId = '[' . config('site.id', 'system-service') . ']';
|
||||
$pids = [];
|
||||
foreach ($this->listProcesses() as $process) {
|
||||
$command = $process['command'];
|
||||
if (!str_contains($command, $siteId)) {
|
||||
continue;
|
||||
}
|
||||
if (!preg_match('/\\]\\..+\\[[0-9]+\\]/', $command)) {
|
||||
continue;
|
||||
}
|
||||
$pids[] = (int)$process['pid'];
|
||||
}
|
||||
|
||||
return $pids;
|
||||
}
|
||||
|
||||
|
||||
private function listProcesses(): array
|
||||
{
|
||||
$lines = [];
|
||||
exec('ps -eo pid=,ppid=,args=', $lines);
|
||||
|
||||
$processes = [];
|
||||
foreach ($lines as $line) {
|
||||
$line = trim($line);
|
||||
if ($line === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$parts = preg_split('/\s+/', $line, 3);
|
||||
if (count($parts) < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$processes[] = [
|
||||
'pid' => (int)$parts[0],
|
||||
'ppid' => (int)$parts[1],
|
||||
'command' => $parts[2],
|
||||
];
|
||||
}
|
||||
|
||||
return $processes;
|
||||
}
|
||||
|
||||
|
||||
private function isProcessAlive(int $pid): bool
|
||||
{
|
||||
return $pid > 1 && @Process::kill($pid, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user