eee
This commit is contained in:
@@ -31,9 +31,13 @@ class State extends Component
|
|||||||
*/
|
*/
|
||||||
public function isRunner(): bool
|
public function isRunner(): bool
|
||||||
{
|
{
|
||||||
|
if ($this->getPidFilePid() !== null || $this->getNamedServerPids() !== []) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
$ports = $this->sortService($this->servers);
|
$ports = $this->sortService($this->servers);
|
||||||
foreach ($ports as $config) {
|
foreach ($ports as $config) {
|
||||||
if (checkPortIsAlready($config['port'])) {
|
if (checkPortIsAlready($config->port)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,13 +51,161 @@ class State extends Component
|
|||||||
*/
|
*/
|
||||||
public function exit($port): void
|
public function exit($port): void
|
||||||
{
|
{
|
||||||
if (!($pid = checkPortIsAlready($port))) {
|
$pids = $this->collectStopPids((int)$port);
|
||||||
|
if ($pids === []) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (checkPortIsAlready($port)) {
|
|
||||||
Process::kill($pid, 0) && Process::kill($pid, SIGTERM);
|
$this->terminatePids($pids, SIGTERM, 30);
|
||||||
usleep(300);
|
|
||||||
|
$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