add dynamic command
This commit is contained in:
parent
bbf15e0e61
commit
ea28665caf
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace LaravelSupportCommand;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class LaravelSupportCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'LaravelSupportCommand
|
||||
{command : The artisan command to monitor (e.g., schedule:work, queue:work)}
|
||||
{--args=* : Additional arguments for the command}
|
||||
{--retry-delay=5 : Seconds to wait before retry on failure}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Monitor and auto-restart any Laravel artisan command if it exits unexpectedly';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$commandToRun = $this->argument('command');
|
||||
$args = $this->option('args');
|
||||
$retryDelay = (int) $this->option('retry-delay');
|
||||
|
||||
// Build full command
|
||||
$fullCommand = "php artisan {$commandToRun}";
|
||||
if (!empty($args)) {
|
||||
$fullCommand .= ' ' . implode(' ', $args);
|
||||
}
|
||||
|
||||
$this->info("=== Laravel Support Command Monitor ===");
|
||||
$this->info("Monitoring: {$fullCommand}");
|
||||
$this->info("Retry delay: {$retryDelay}s");
|
||||
$this->line('');
|
||||
|
||||
// Kill existing processes on startup (Unix only)
|
||||
if (!$this->isWindows()) {
|
||||
$this->warn("Killing any existing '{$commandToRun}' processes...");
|
||||
exec("pkill -f 'artisan {$commandToRun}'");
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$restartCount = 0;
|
||||
|
||||
while (true) {
|
||||
if ($restartCount > 0) {
|
||||
$this->warn("Restart #{$restartCount} - Cleaning up processes...");
|
||||
$this->killExistingProcesses($commandToRun);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
$this->info("[" . date('Y-m-d H:i:s') . "] Starting: {$fullCommand}");
|
||||
|
||||
$process = proc_open(
|
||||
$fullCommand,
|
||||
[
|
||||
0 => ['pipe', 'r'], // stdin
|
||||
1 => ['pipe', 'w'], // stdout
|
||||
2 => ['pipe', 'w'], // stderr
|
||||
],
|
||||
$pipes,
|
||||
base_path(), // Working directory
|
||||
null
|
||||
);
|
||||
|
||||
if (is_resource($process)) {
|
||||
// Close stdin as we don't need it
|
||||
fclose($pipes[0]);
|
||||
|
||||
// Set streams to non-blocking
|
||||
stream_set_blocking($pipes[1], false);
|
||||
stream_set_blocking($pipes[2], false);
|
||||
|
||||
$status = proc_get_status($process);
|
||||
$this->comment("Process started with PID: {$status['pid']}");
|
||||
|
||||
// Monitor output
|
||||
while (true) {
|
||||
$status = proc_get_status($process);
|
||||
|
||||
// Check if process is still running
|
||||
if (!$status['running']) {
|
||||
$exitCode = $status['exitcode'];
|
||||
$this->newLine();
|
||||
$this->error("Process exited with code: {$exitCode}");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read stdout
|
||||
while ($line = fgets($pipes[1])) {
|
||||
$this->line(trim($line));
|
||||
}
|
||||
|
||||
// Read stderr
|
||||
while ($err = fgets($pipes[2])) {
|
||||
$this->error(trim($err));
|
||||
}
|
||||
|
||||
usleep(100000); // Sleep 0.1s to prevent CPU spinning
|
||||
}
|
||||
|
||||
// Clean up
|
||||
fclose($pipes[1]);
|
||||
fclose($pipes[2]);
|
||||
proc_close($process);
|
||||
|
||||
$restartCount++;
|
||||
$this->warn("Retrying in {$retryDelay} seconds...");
|
||||
sleep($retryDelay);
|
||||
|
||||
} else {
|
||||
$this->error('Failed to start process. Retrying in ' . $retryDelay . ' seconds...');
|
||||
sleep($retryDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if running on Windows
|
||||
*/
|
||||
protected function isWindows(): bool
|
||||
{
|
||||
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill existing processes
|
||||
*/
|
||||
protected function killExistingProcesses(string $command): void
|
||||
{
|
||||
if ($this->isWindows()) {
|
||||
// Windows: harder to target specific commands
|
||||
exec('taskkill /F /FI "WINDOWTITLE eq ' . $command . '" 2>NUL');
|
||||
} else {
|
||||
// Unix: kill by command pattern
|
||||
exec("pkill -f 'artisan {$command}' 2>/dev/null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,8 @@ class LaravelSupportCommandServiceProvider extends ServiceProvider
|
|||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
QueueWorkCommand::class,
|
||||
ScheduleWorkCommand::class
|
||||
ScheduleWorkCommand::class,
|
||||
LaravelSupportCommand::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue