mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Add command to restart tmux if monitor pane is dead
This commit is contained in:
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Settings;
|
||||||
|
use App\Services\Tmux\TmuxSessionManager;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
|
||||||
|
class TmuxHealthCheck extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'tmux:health-check
|
||||||
|
{--session= : Tmux session name}
|
||||||
|
{--auto-restart : Automatically restart tmux if monitor pane is dead}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Check if tmux session exists and monitor pane is alive, optionally restart if dead';
|
||||||
|
|
||||||
|
private TmuxSessionManager $sessionManager;
|
||||||
|
|
||||||
|
private string $sessionName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle(): int
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// Get session name from option, database setting, or config
|
||||||
|
$this->sessionName = $this->option('session')
|
||||||
|
?? Settings::settingValue('tmux_session')
|
||||||
|
?? config('tmux.session.default_name', 'nntmux');
|
||||||
|
|
||||||
|
$this->sessionManager = new TmuxSessionManager($this->sessionName);
|
||||||
|
|
||||||
|
// Use Laravel's built-in quiet mode check
|
||||||
|
$quiet = $this->output->isQuiet();
|
||||||
|
|
||||||
|
// Step 1: Check if tmux session exists
|
||||||
|
if (! $this->sessionManager->sessionExists()) {
|
||||||
|
if (! $quiet) {
|
||||||
|
$this->warn("⚠️ Tmux session '{$this->sessionName}' does not exist.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $quiet) {
|
||||||
|
$this->info("✅ Tmux session '{$this->sessionName}' exists.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Check if monitor pane (0.0) is dead
|
||||||
|
$monitorPaneDead = $this->isMonitorPaneDead();
|
||||||
|
|
||||||
|
if ($monitorPaneDead) {
|
||||||
|
if (! $quiet) {
|
||||||
|
$this->warn('⚠️ Monitor pane (0.0) is dead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->option('auto-restart')) {
|
||||||
|
return $this->restartTmux();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $quiet) {
|
||||||
|
$this->info('✅ Monitor pane (0.0) is alive and running.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error('❌ Health check failed: '.$e->getMessage());
|
||||||
|
logger()->error('Tmux health check error', [
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the monitor pane (0.0) is dead.
|
||||||
|
*/
|
||||||
|
private function isMonitorPaneDead(): bool
|
||||||
|
{
|
||||||
|
// Use tmux display-message to check pane_dead flag
|
||||||
|
$result = Process::timeout(10)->run(
|
||||||
|
"tmux display-message -p -t {$this->sessionName}:0.0 '#{pane_dead}'"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $result->successful()) {
|
||||||
|
// If we can't even query the pane, consider it dead
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paneDeadFlag = trim($result->output());
|
||||||
|
|
||||||
|
// tmux returns '1' if pane is dead, '0' if alive
|
||||||
|
if ($paneDeadFlag === '1') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional check: verify the pane is actually running a process
|
||||||
|
$commandResult = Process::timeout(10)->run(
|
||||||
|
"tmux display-message -p -t {$this->sessionName}:0.0 '#{pane_current_command}'"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $commandResult->successful()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentCommand = trim($commandResult->output());
|
||||||
|
|
||||||
|
// If the pane is just showing a shell with no process, it might be considered "idle"
|
||||||
|
// but not necessarily dead. The pane_dead flag is the authoritative check.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restart the tmux session.
|
||||||
|
*/
|
||||||
|
private function restartTmux(): int
|
||||||
|
{
|
||||||
|
$this->info('🔄 Restarting tmux session...');
|
||||||
|
|
||||||
|
// First, stop the existing session if it exists
|
||||||
|
if ($this->sessionManager->sessionExists()) {
|
||||||
|
$this->info('⏹️ Stopping existing session...');
|
||||||
|
$this->call('tmux:stop', [
|
||||||
|
'--session' => $this->sessionName,
|
||||||
|
'--force' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Give it a moment to clean up
|
||||||
|
sleep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a new session
|
||||||
|
$this->info('▶️ Starting new tmux session...');
|
||||||
|
$exitCode = $this->call('tmux:start', [
|
||||||
|
'--session' => $this->sessionName,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($exitCode === Command::SUCCESS) {
|
||||||
|
$this->info("✅ Tmux session '{$this->sessionName}' restarted successfully.");
|
||||||
|
} else {
|
||||||
|
$this->error("❌ Failed to restart tmux session '{$this->sessionName}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $exitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+11
-11
@@ -2817,16 +2817,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v12.45.1",
|
"version": "v12.46.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "1ca7e2a2ee17ae5bc435af7cb52d2f130148e2fa"
|
"reference": "9dcff48d25a632c1fadb713024c952fec489c4ae"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/1ca7e2a2ee17ae5bc435af7cb52d2f130148e2fa",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/9dcff48d25a632c1fadb713024c952fec489c4ae",
|
||||||
"reference": "1ca7e2a2ee17ae5bc435af7cb52d2f130148e2fa",
|
"reference": "9dcff48d25a632c1fadb713024c952fec489c4ae",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -3035,7 +3035,7 @@
|
|||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2026-01-07T00:50:24+00:00"
|
"time": "2026-01-07T23:26:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/horizon",
|
"name": "laravel/horizon",
|
||||||
@@ -14810,16 +14810,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "friendsofphp/php-cs-fixer",
|
"name": "friendsofphp/php-cs-fixer",
|
||||||
"version": "v3.92.4",
|
"version": "v3.92.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||||
"reference": "9e7488b19403423e02e8403cc1eb596baf4673b0"
|
"reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/9e7488b19403423e02e8403cc1eb596baf4673b0",
|
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58",
|
||||||
"reference": "9e7488b19403423e02e8403cc1eb596baf4673b0",
|
"reference": "260cc8c4a1d2f6d2f22cd4f9c70aa72e55ebac58",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@@ -14902,7 +14902,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.92.4"
|
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.92.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -14910,7 +14910,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2026-01-04T00:38:52+00:00"
|
"time": "2026-01-08T21:57:37+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "hamcrest/hamcrest-php",
|
"name": "hamcrest/hamcrest-php",
|
||||||
|
|||||||
@@ -49,3 +49,5 @@ if (config('nntmux.purge_inactive_users') === true) {
|
|||||||
Schedule::job(new RemoveInactiveAccounts)->daily();
|
Schedule::job(new RemoveInactiveAccounts)->daily();
|
||||||
Schedule::job(new PurgeDeletedAccounts)->daily();
|
Schedule::job(new PurgeDeletedAccounts)->daily();
|
||||||
}
|
}
|
||||||
|
// Check tmux health and auto-restart if monitor pane is dead
|
||||||
|
Schedule::command('tmux:health-check --auto-restart')->everyThirtyMinutes()->withoutOverlapping();
|
||||||
|
|||||||
Reference in New Issue
Block a user