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",
"autoload": {
"psr-4": {
@ -19,7 +19,7 @@
"extra": {
"laravel": {
"providers": [
"Kai\\HelloCommand\\HelloCommandServiceProvider"
"Kai\\KaiCommand\\KaiCommandServiceProvider"
]
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace Kai\HelloCommand;
namespace Kai\KaiCommand;
use Illuminate\Support\ServiceProvider;
class HelloCommandServiceProvider extends ServiceProvider
class KaiCommandServiceProvider extends ServiceProvider
{
/**
* Register any application services.
@ -25,7 +25,9 @@ class HelloCommandServiceProvider extends ServiceProvider
{
if ($this->app->runningInConsole()) {
$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
namespace Kai\HelloCommand;
namespace Kai\KaiCommand;
use Illuminate\Console\Command;
class HelloCommand extends Command
class KaiHelloCommand extends Command
{
/**
* The name and signature of the console command.
@ -12,7 +12,7 @@ class HelloCommand extends Command
*
* @var string
*/
protected $signature = 'hello:world {name?}';
protected $signature = 'KaiHello';
/**
* The console command description.
@ -28,9 +28,8 @@ class HelloCommand extends Command
*/
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;
}

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);
}
}
}
}