Skip to content

Commit 1ff1f50

Browse files
Add signal handling for graceful shutdown and cleanup
- Implement SIGINT and SIGTERM signal handlers using pcntl extension - Add cleanup handler registration system for plugins - Use logger with notice level instead of direct output - Allow plugins to register cleanup handlers via getInstance() and registerCleanupHandler() - Gracefully handle cases where pcntl extension is not available 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 3e2a0a8 commit 1ff1f50

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

src/Terminus.php

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ class Terminus implements
8282

8383
private Application $application;
8484

85+
/**
86+
* @var callable[]
87+
*/
88+
private $cleanup_handlers = [];
89+
90+
/**
91+
* @var static
92+
*/
93+
private static $instance;
94+
8595
/**
8696
* Object constructor
8797
*
@@ -91,6 +101,7 @@ class Terminus implements
91101
*/
92102
public function __construct(Config $config, InputInterface $input, OutputInterface $output)
93103
{
104+
self::$instance = $this;
94105
$this->setConfig($config);
95106
$this->setInput($input);
96107
$this->setOutput($output);
@@ -514,6 +525,10 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu
514525
if ($output === null) {
515526
$output = $this->output();
516527
}
528+
529+
// Set up signal handlers for graceful shutdown
530+
$this->setupSignalHandlers();
531+
517532
$config = $this->getConfig();
518533
if (!empty($cassette = $config->get('vcr_cassette')) && !empty($mode = $config->get('vcr_mode'))) {
519534
$this->startVCR(array_merge(compact('cassette'), compact('mode')));
@@ -525,6 +540,82 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu
525540
return $status_code;
526541
}
527542

543+
/**
544+
* Set up signal handlers for graceful shutdown
545+
*/
546+
private function setupSignalHandlers(): void
547+
{
548+
if (!function_exists('pcntl_signal')) {
549+
// pcntl extension not available, signal handling not possible
550+
return;
551+
}
552+
553+
// Handle SIGINT (Ctrl+C) and SIGTERM
554+
pcntl_signal(SIGINT, [$this, 'handleSignal']);
555+
pcntl_signal(SIGTERM, [$this, 'handleSignal']);
556+
557+
// Enable signal handling
558+
pcntl_async_signals(true);
559+
}
560+
561+
/**
562+
* Handle signals for graceful shutdown
563+
*
564+
* @param int $signal The signal number
565+
*/
566+
public function handleSignal(int $signal): void
567+
{
568+
$this->logger->notice('Received signal {signal}, performing cleanup...', ['signal' => $signal]);
569+
570+
$this->cleanup();
571+
572+
// Restore default signal handler and re-raise the signal
573+
pcntl_signal($signal, SIG_DFL);
574+
posix_kill(posix_getpid(), $signal);
575+
}
576+
577+
/**
578+
* Get the current Terminus instance
579+
*
580+
* @return static|null
581+
*/
582+
public static function getInstance(): ?self
583+
{
584+
return self::$instance;
585+
}
586+
587+
/**
588+
* Register a cleanup handler that will be called during signal handling
589+
*
590+
* @param callable $handler The cleanup handler function
591+
*/
592+
public function registerCleanupHandler(callable $handler): void
593+
{
594+
$this->cleanup_handlers[] = $handler;
595+
}
596+
597+
/**
598+
* Perform cleanup operations
599+
*/
600+
private function cleanup(): void
601+
{
602+
try {
603+
// Call all registered cleanup handlers
604+
foreach ($this->cleanup_handlers as $handler) {
605+
try {
606+
call_user_func($handler);
607+
} catch (\Exception $e) {
608+
$this->logger->error('Error in cleanup handler: {message}', ['message' => $e->getMessage()]);
609+
}
610+
}
611+
612+
// Clear any active locks or temporary files
613+
$this->logger->notice('Cleanup completed.');
614+
} catch (\Exception $e) {
615+
$this->logger->error('Error during cleanup: {message}', ['message' => $e->getMessage()]);
616+
}
617+
}
618+
528619
/**
529620
* Starts and configures PHP-VCR
530621
*

0 commit comments

Comments
 (0)