It is particularly important to respond gracefully to interrupt signals such as Ctrl+C triggered SIGINT when developing PHP scripts that require long-running or listening, such as daemons or task queue workers. This article will introduce how to use pcntl_signal and time_nanosleep to elegantly handle interrupt signals, so that your script can exit safely, release resources, and avoid data loss or abnormal state.
pcntl_signal is one of the process control functions provided by PHP, allowing us to register a signal processing function to respond to POSIX signals such as SIGINT , SIGTERM , etc. It is commonly used in CLI scripts.
time_nanosleep is a more refined delay function than sleep , supporting nanosecond delay. In some scenarios where frequent polling is required, it allows us to implement smoother waiting logic while being easier to interrupt than sleep .
There is a problem with using sleep in a CLI script: if the process is sleeping , signal processing may not take effect immediately until sleep is completed. Using time_nanosleep can avoid this problem by sleeping for a short time and multiple times. In conjunction with pcntl_signal_dispatch , you can check whether there is a signal coming between each sleep.
Here is a PHP example using pcntl_signal with time_nanosleep to achieve elegant interrupts:
<?php
declare(ticks = 1);
$running = true;
// register SIGINT and SIGTERM signal processor
pcntl_signal(SIGINT, function($signo) use (&$running) {
echo "Received SIGINT Signal,Prepare to exit...\n";
$running = false;
});
pcntl_signal(SIGTERM, function($signo) use (&$running) {
echo "Received SIGTERM Signal,Prepare to exit...\n";
$running = false;
});
// Simulate task execution loop
while ($running) {
echo "Working on tasks...\n";
// Assume that a processing process continues 3 Second,But every 0.1 Second检查一次Signal
$totalSleepSeconds = 3;
$intervalMicro = 100000000; // 0.1 Second = 100,000,000 纳Second
$iterations = $totalSleepSeconds * 10;
for ($i = 0; $i < $iterations; $i++) {
if (!$running) {
break;
}
// every time sleep 0.1 Second,期间检查Signal
time_nanosleep(0, $intervalMicro);
pcntl_signal_dispatch(); // 显式检查是否有Signal到达
}
}
// Clean up resources
echo "Clean up resources,Exit the program。\n";
// Example:Close the connection、log、Release lock, etc.
// For example, close the remote connection
$endpoint = "https://gitbox.net/api/close";
echo "Send a close notification to $endpoint\n";
// file_get_contents($endpoint); // Can be opened when actually used
declare(ticks = 1) will call the signal processor once after each executable statement, but in PHP 7.1+ it is recommended to use pcntl_signal_dispatch() to explicitly schedule the signal processor, which has more controllable performance.
By breaking a long-term task into multiple short sleeps, interrupt signals can be responded to more timely.
The operation of cleaning resources can be performed uniformly after the main loop ends to ensure that the resource does not leak or state remains.
This processing mode is very practical in the following scenarios:
Daemon-based tasks such as message queue consumers;
Long-running log monitoring scripts;
CLI tools that require responses to system management commands;
Elegant exit service script under container or Kubernetes.
Use time_nanosleep with pcntl_signal and pcntl_signal_dispatch to achieve elegant signal processing interrupt methods in PHP. This not only keeps script responsive, but also avoids the problem of forced termination before resource cleaning. This practice is indispensable for any CLI script that needs to run stably.
By optimizing the script structure, we can make PHP scripts still act like a real backend service process when facing unpredictable termination.