I had some several scripts that were running for a long time (6+ hours).
They were all containing a main loop that did it's thing, and a registered shutdown function that triggered a mysql query to announce the process as "done".
I decided to use pcntl_fork() inside these main loops, to run each round as a different process, in order to make the entire script complete faster.
It works OK, but, each child process is still registered with the shutdown function.
Therefore, each time a child process is complete it calls that mysql query and announce the script as complete.
How can I disable that shutdown function for the child processes, but keep it alive for the parent?
Sample code to understand what's going on:
common.php
register_shutdown_function('shutdown');
function shutdown()
{ global $objDb,$arg_id ;
echo "\n\n Executing queue process shutdown function.";
$objDb->query("UPDATE queue_args SET done='1' WHERE id='{$arg_id}'");
}
loop.php
include('common.php');
for ($i=1;$i<=200;$i++){
$pid = pcntl_fork();
if (!$pid) {
//child proccess - do something without calling the shutdown function
posix_kill(getmypid(),9);
}
} exit(); //this is when the shutdown function should eventually be called
Thanks
You could register the shutdown function within the if, like this:
if ($pid) {
if(!$registered) {
$registered = true;
register_shutdown_function('shutdown');
}
}else{
//child proccess - do something without calling the shutdown function
posix_kill(getmypid(),9);
}
You can't.
You could set a flag in the child processes after forking and poll it in the shutdown function - if it's set then return early. Or store the parent pid before you fork and, inside the shutdown function, return early if that's not the current pid. Or register the function in the parent process after forking.
if (!$pid) { posix_kill(getmypid(),9); }
This is really bad way to prevent the shutdown function from being invoked in the child process - but has all sorts of other implications - PHP won't shut down cleanly, buffers won't be flushed. Maybe you just need to do this:
#!/usr/bin/php
<?php
$arg_id = exec('task_which_forks.php');
exec("queue_clean_up.php $arg_id");
Related
I'm writing a daemon in PHP 5.6. So far, it is basically a Daemon class with a mainLoop() method that has an infinite loop. In each iteration, the mainLoop executes a series of steps.
I need it to implement a "graceful kill" mechanism: if a SIGINT or SIGTERM arrive, the daemon must complete the current step of the current iteration before dying.
My idea is to use a static variable Daemon::CONTINUE TRUE by default; when a SIGINT or SIGTERM arrives, it is set to FALSE.
In each iteration, before passing to the next step the daemon checks if self::CONTINUE has switched to FALSE and, if it has, it returns.
I know that the way to do this is to use pcntl_signal. It seems that I can either use it with declare(ticks=1) or with pcntl_signal_dispatch(), but I'm not sure about the difference.
Does declare(ticks=1) make the process check for the arrival of signals after each tick, whereas pcntl_signal_dispatch() explicitly checks the signals only when I call it?
These are snippets of the two ways I described before. Are they both correct? Which one should I use?
Way 1
<?php
declare(ticks=1) {
pcntl_signal(SIGINT, function($signo) {Daemon::CONTINUE = FALSE;});
pcntl_signal(SIGTERM, function($signo) {Daemon::CONTINUE = FALSE;});
}
public class Daemon {
public static $CONTINUE = TRUE;
function mainLoop() {
...
if (self::CONTINUE === FALSE)
return;
...
}
}
Way 2
<?php
pcntl_signal(SIGINT, function($signo) {Daemon::CONTINUE = FALSE;});
pcntl_signal(SIGTERM, function($signo) {Daemon::CONTINUE = FALSE;});
public class Daemon {
public static $CONTINUE = TRUE;
function mainLoop() {
...
pcntl_signal_dispatch();
if (self::CONTINUE === FALSE)
return;
...
}
}
Thanks for your support.
Ok, after some testing and debugging I tried both solutions.
I'll leave here my observations in case somebody encounters my same issues.
It seems that the way 1 with declare(ticks=1) does not work; I can not understand why.
The way 2 with pcntl_signal_dispatch(), on the contrary, seems to work nice.
After deeper research, I think that the way 2 is the best one for my case anyway.
In fact, declare(tick=1), if it worked, would run the pcntl_signal on each tick, roughly corresponding to the execution of each code line.
This can potentially degradate the performances.
On the contrary, apparently pcntl_signal_dispatch) just handles pending signals when it is called, so it should be lighter on performances.
This is the sample code, I'm working on
class workerThread extends Thread {
public function __construct($i){
$this->i=$i;
}
public function run(){
while(true){
echo $this->i;
sleep(1);
}
}
}
for($i=0;$i<50;$i++){
$workers[$i]=new workerThread($i);
$workers[$i]->start();
}
What is the appropriate way to get return value from run() or should create another function for callback?
well first you have to wait for all threads to finish.
so after your initial loop you should do one more loop waiting for each worker to finish. there is thread->join function that syncs your main thread with the sub-thread. causing to halt the execution and wait until the sub thread finishes. so if you call if($worker->join()) {...} you can be sure, that the worker is done working :)
http://php.net/manual/de/thread.join.php
second, a thread does not return a value. instead create a variable in your class, for example result and fill it with data during the run of a thread. collect at the end (after join) the $worker->result
third, your current threads even cannot report any result, as they run for ever. From the question I dont understand, if you want them to run for ever? Because if you do there are more complicated steps involved to get the results continuously.
Unfortunately calling php exit() on php-fpm/nginx configuration does not stop the script immediately while file handles might not be closed.
Some developers suggest calling fastcgi_finish_request() but also this does not stop the script.
Others suggest wrapping all code in a catch block:
<?php
class SystemExit extends Exception {}
try {
/* PUT ALL THE CODE HERE */
} catch (SystemExit $e) { /* do nothing */ }
?>
and throwing an exception where code stop is needed:
if (SOME_EXIT_CONDITION)
throw new SystemExit(); // instead of exit()
This would mean editing all php files to include try/catch block and seems tedious to me.
Are there any other clean solutions?
So we found out that it's a register_shutdown_function callback that prevents your script from exiting immediately.
PHP shutdown function is designed to be called on any script shutdown when possible. But it has a feature: if one of shutdown callbacks calls exit — script is exiting without calling any other callbacks.
So if you really want to skip a shutdown function in some cases, you should register some killer-function as a very first shutdown callback. Inside that killer-function you will check a kind of singleton for state: do we want to exit? — call exit(), otherwise — return.
<?php
function killer_function() {
if ($someGlobalThing->needToExitRightNow()) {
exit();
}
}
register_shutdown_function('killer_function');
// ...
function exit_now() {
$someGlobalThing->exitNow();
exit();
}
($someGlobalThing can be a singleton or some super-global variable or a global registry or whatever you like)
Then calling exit_now() will do the trick.
I have a Symfony Console command that iterates over a potentially big collection of items and does a task with each of them. Since the collection can be big, the command can take a long time to run (hours). Once the command finishes, it displays some statistics.
I'd like to make it possible to abort the command in a nice way. Right now if I abort it (ie with ctrl+c in the CLI), there is no statistics summary and no way to output the parameters needed to resume the command. Another issue is that the command might be terminated in the middle of handling an item - it'd be better if it could only terminate in between handling items.
So is there a way to tell a command to "abort nicely as soon as possible", or have the ctrl+c command be interpreted as such?
I tried using the ConsoleEvents::TERMINATE event, though the handlers for this only get fired on command completion, not when I ctrl+c the thing. And I've not been able to find further info on making such resumable commands.
This is what worked for me. You need to call pcntl_signal_dispatch before the signal handlers are actually executed. Without it, all tasks will finish first.
<?php
use Symfony\Component\Console\Command\Command;
class YourCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
pcntl_signal(SIGTERM, [$this, 'stopCommand']);
pcntl_signal(SIGINT, [$this, 'stopCommand']);
$this->shouldStop = false;
foreach ( $this->tasks as $task )
{
pcntl_signal_dispatch();
if ( $this->shouldStop ) break;
$task->execute();
}
$this->showSomeStats($output);
}
public function stopCommand()
{
$this->shouldStop = true;
}
}
You should take a look at RabbitMqBundle's signal handling. Its execute method just links some callbacks via the pcntl_signal() function call. A common case should look pretty much like this:
<?php
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand as Command;
class YourCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output)
{
pcntl_signal(SIGTERM, array(&$this, 'stopCommand', $output));
pcntl_signal(SIGINT, array(&$this, 'stopCommand', $output));
pcntl_signal(SIGHUP, array(&$this, 'restartCommand', $output));
// The real execute method body
}
public function stopCommand(OutputInterface $output)
{
$output->writeln('Stopping');
// Do what you need to stop your process
}
public function restartCommand(OutputInterface $output)
{
$output->writeln('Restarting');
// Do what you need to restart your process
}
}
The answers are more complex than they need to be. Sure, you can register POSIX signal handlers, but if the only signals that need to be handled are basic interrupts and the like, you should just define a destructor on the Command.
class YourCommand extends Command
{
// Other code goes here.
__destruct()
{
$this->shouldStop = true;
}
}
A case where you would want to register a POSIX signal is for the SIGCONT signal, which can handle the resumption of a process that was stopped (SIGSTOP).
Another case would be where you want every signal to behave differently; for the most part, though, SIGINT and SIGTERM and a handful of others would be registered with the same "OMG THE PROCESS HAS BEEN KILLED" operation.
Aside from these examples, registering signal events is unnecessary. This is why destructors exist.
You can even extend Symfony's base Command class with a __destruct method, which would automatically provide cleanup for every command; should a particular command require additional operations, just overwrite it.
I was testing a class whilst developing my app and just like any other quick-lazy-method-tweak I did an echo in
function __construct(){
parent::__construct();
echo "yaba daba doo";
exit();
}
Now, after few tests and all, I thought of checking if the class has been fully compiled thus I wrote:
function __destruct(){
echo "ends here";
exit();
}
Interestingly, even though there was an exit in __construct , it still executed __destruct!
As per my knowledge exit 'kills' the process, doesn't it?
__destruct is called upon when the object has no more reference for the class.
Does that mean, exit(0) does not kill the process on priority?
Is it a PHP bug? because, IMO the script shouldn't go any further?
It's all in the manual.
The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.