Lae/app/Console/Commands/Cluster/Work.php

223 lines
5.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Console\Commands\Cluster;
use App\Support\ClusterSupport;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Str;
use Symfony\Component\Console\Command\Command as CommandAlias;
class Work extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'works';
/**
* The console command description.
*
* @var string
*/
protected $description = '启动此应用程序。';
/**
* Execute the console command.
*
* @return int
*/
public function handle(): int
{
// 检测目录下是否有 rr
if (! file_exists(base_path('rr'))) {
$this->warn('未找到 rr 文件,将自动下载。');
// 获取操作系统是 darwin 还是 linux
$os = Str::contains(PHP_OS, 'Darwin') ? 'darwin' : 'linux';
// 获取操作系统是 arm64 还是 amd64
$arch = Str::contains(php_uname('m'), ['aarch64', 'arm64']) ? 'arm64' : 'amd64';
// 下载 rr
$this->info('正在下载 rr。');
$version = config('settings.roadrunner.version');
$download_link = "https://github.sakurapuare.com/roadrunner-server/roadrunner/releases/download/v$version/roadrunner-$version-$os-$arch.tar.gz";
$save_name = 'rr_download.tar.gz';
// 下载wget
exec("wget $download_link -O $save_name");
exec("tar -zxvf $save_name");
// 删除下载的压缩包
exec("rm $save_name");
// 提取解压目录下的 rr 文件
exec("mv roadrunner-$version-$os-$arch/rr rr");
// 删除解压目录
exec("rm -rf roadrunner-$version-$os-$arch");
// 设置 rr 可执行权限
exec('chmod +x rr');
}
// 关闭 Octane
Artisan::call('octane:stop');
if (! config('settings.node.ip')) {
$this->error('请先配置节点 IP。');
return CommandAlias::FAILURE;
}
// 刷新配置缓存
$this->info('正在刷新配置缓存。');
Artisan::call('config:cache');
Artisan::call('route:cache');
// redis 创建一个 hash
$this->info('正在注册节点。');
ClusterSupport::registerThisNode();
$this->info('初始化完成。');
$this->info('正在启动集群协调任务。');
$pid = pcntl_fork();
if ($pid === -1) {
$this->error('无法创建子进程。');
return CommandAlias::FAILURE;
} elseif ($pid === 0) {
// 再打开一个,负责 octane
$pid = pcntl_fork();
if ($pid === -1) {
$this->error('无法创建子进程。');
return CommandAlias::FAILURE;
} elseif ($pid === 0) {
// 子进程
$this->info('正在启动 Web。');
$command = 'php artisan octane:start --host=0.0.0.0 --rpc-port=6001 --port=8000';
$this->pipeCommand($command);
} else {
$this->report();
}
} else {
// 父进程
$this->work();
}
return CommandAlias::SUCCESS;
}
private function pipeCommand($command): void
{
$descriptor_spec = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
];
$pipes = [];
$process = proc_open($command, $descriptor_spec, $pipes);
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
echo $s;
}
}
// 命令结束后,关闭管道
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
// 关闭进程
proc_close($process);
}
private function report(): void
{
$this->info('正在报告此系统,请保持此命令一直运行。');
Artisan::call('config:cache');
$cpu = $this->getCpuUsage();
while (1) {
ClusterSupport::publish('system_usage', [
'cpu' => $cpu,
]);
sleep(1);
}
}
private function getCpuUsage(): float
{
// 获取 CPU 使用率
$cpu = sys_getloadavg();
return $cpu[0];
}
private function work(): void
{
$this->info('正在监听任务。');
ClusterSupport::publish('node.online');
ClusterSupport::listen('*', function ($event, $message) {
$this->dispatchEvent($event, $message);
}, false);
}
private function dispatchEvent($event, $message = []): void
{
$events = [
'config.updated' => function () {
$this->info('正在更新配置文件。');
Artisan::call('cluster:sync', [
'--force' => 'true',
]);
$this->info('配置文件更新完成。');
},
'cluster.restart.web' => function () {
$this->info('正在重启 Web。');
exec('php artisan octane:reload');
ClusterSupport::publish('cluster.restarted.web');
$this->info('Web 重启完成。');
},
'cluster.restart.all' => function () {
$this->info('正在重启整个莱云。');
$this->pipeCommand('supervisorctl restart all');
ClusterSupport::publish('cluster.restarted.all');
$this->info('整个莱云 重启完成。');
},
];
if (isset($events[$event])) {
$this->warn("正在处理 $event 事件。");
$events[$event]($message);
}
}
}