first commit

This commit is contained in:
root 2025-10-22 06:02:24 +00:00
parent 2e3a64ebe4
commit 212ce28396
5 changed files with 164 additions and 10 deletions

View File

@ -1,5 +1,5 @@
{ {
"name": "kai/hello-command", "name": "kai/KaiCommand",
"type": "laravel-package", "type": "laravel-package",
"autoload": { "autoload": {
"psr-4": { "psr-4": {
@ -19,7 +19,7 @@
"extra": { "extra": {
"laravel": { "laravel": {
"providers": [ "providers": [
"Kai\\HelloCommand\\HelloCommandServiceProvider" "Kai\\KaiCommand\\KaiCommandServiceProvider"
] ]
} }
} }

View File

@ -1,10 +1,10 @@
<?php <?php
namespace Kai\HelloCommand; namespace Kai\KaiCommand;
use Illuminate\Support\ServiceProvider; use Illuminate\Support\ServiceProvider;
class HelloCommandServiceProvider extends ServiceProvider class KaiCommandServiceProvider extends ServiceProvider
{ {
/** /**
* Register any application services. * Register any application services.
@ -25,7 +25,9 @@ class HelloCommandServiceProvider extends ServiceProvider
{ {
if ($this->app->runningInConsole()) { if ($this->app->runningInConsole()) {
$this->commands([ $this->commands([
HelloCommand::class, // Đăng ký Command Class của bạn KaiHelloCommand::class,
QueueWorkCommand::class,
ScheduleWorkCommand::class
]); ]);
} }
} }

View File

@ -1,10 +1,10 @@
<?php <?php
namespace Kai\HelloCommand; namespace Kai\KaiCommand;
use Illuminate\Console\Command; use Illuminate\Console\Command;
class HelloCommand extends Command class KaiHelloCommand extends Command
{ {
/** /**
* The name and signature of the console command. * The name and signature of the console command.
@ -12,7 +12,7 @@ class HelloCommand extends Command
* *
* @var string * @var string
*/ */
protected $signature = 'hello:world {name?}'; protected $signature = 'KaiHello';
/** /**
* The console command description. * The console command description.
@ -28,9 +28,8 @@ class HelloCommand extends Command
*/ */
public function handle() public function handle()
{ {
$name = $this->argument('name') ?? 'World';
$this->info("Hello, {$name}! This command runs from your package."); $this->info("Hello, Kai! This command runs from your package.");
return Command::SUCCESS; return Command::SUCCESS;
} }

85
src/QueueWorkCommand.php Normal file
View File

@ -0,0 +1,85 @@
<?php
namespace Kai\KaiCommand;
use Illuminate\Console\Command;
class QueueWorkCommand extends Command
{
protected $signature = 'QueueWork {--workers=3 : Number of workers to run}';
protected $description = 'Run multiple artisan queue:work processes, restart them if they exit.';
public function handle(): never
{
$workers = (int) $this->option('workers');
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$this->warn('Killing any existing queue:work processes...');
exec('pkill -f "artisan queue:work"');
}
$this->info("Starting {$workers} queue:work processes...");
$processes = [];
$pipesList = [];
for ($i = 1; $i <= $workers; $i++) {
$this->info("Launching worker {$i}...");
$descriptors = [
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'], // stderr
];
$process = proc_open('php artisan queue:work', $descriptors, $pipes);
if (is_resource($process)) {
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$processes[$i] = $process;
$pipesList[$i] = $pipes;
}
}
// Monitor loop
while (true) {
foreach ($processes as $i => $process) {
if (is_resource($process)) {
$status = proc_get_status($process);
// Read stdout
$out = stream_get_contents($pipesList[$i][1]);
if ($out !== '') {
foreach (explode("\n", trim($out)) as $line) {
if ($line !== '') {
$this->info("[Worker {$i}] " . $line);
}
}
}
// Read stderr
$err = stream_get_contents($pipesList[$i][2]);
if ($err !== '') {
foreach (explode("\n", trim($err)) as $line) {
if ($line !== '') {
$this->error("[Worker {$i}] " . $line);
}
}
}
// Restart if stopped
if (!$status['running']) {
$this->warn("Worker {$i} stopped. Restarting...");
proc_close($process);
$process = proc_open('php artisan queue:work', [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
], $pipes);
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
$processes[$i] = $process;
$pipesList[$i] = $pipes;
}
}
}
usleep(200000); // 0.2s pause to avoid busy loop
}
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace Kai\KaiCommand;
use Illuminate\Console\Command;
class ScheduleWorkCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ScheduleWork';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run artisan schedule:work, and if it exits, kill and restart it.';
public function handle()
{
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$this->warn('Killing any existing schedule:work monitor processes using pkill...');
exec('pkill -f "schedule:work"');
}
$this->info('Starting schedule:work monitor...');
while (true) {
$this->warn('Killing any remaining schedule:work processes...');
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
exec('taskkill /IM php.exe /F /FI "WINDOWTITLE eq schedule:work"');
} else {
exec('pkill -f "artisan schedule:work"');
}
$this->info('Starting: php artisan schedule:work');
$process = proc_open(
'php artisan schedule:work',
[
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
],
$pipes
);
if (is_resource($process)) {
// Read output and error
while ($line = fgets($pipes[1])) {
$this->line(trim($line));
}
while ($err = fgets($pipes[2])) {
$this->error(trim($err));
}
fclose($pipes[1]);
fclose($pipes[2]);
$status = proc_get_status($process);
$pid = $status['pid'] ?? null;
proc_terminate($process);
return $pid;
} else {
$this->error('Failed to start schedule:work process. Retrying in 5 seconds...');
sleep(5);
}
}
}
}