PHP 5.6 signal handling: declare(ticks=1) vs pcntl_signal_dispatch() - php

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.

Related

Is it good practice to die or exit in long scripts (PHP)

I've looked at different answers and except for this one that talks about die while testing and generating errors, I want to know if die() has a negative impact on my code when it is useless to continue executing.
For example, if I have a long script with many conditionals, at a given point, once the condition that I was looking for is successful I don't need my script to keep on testing the other conditions.
$a = 'a';
if($a == 'a'){
//long script
die();
}
if($b == 'a'){
//long script
die();
}
if($c == 'a'){
//long script
die();
}
This is a simple and maybe silly example, with other more elegant solutions, but it helps explain my question; if I die() on the first condition, it will stop from executing the rest of the code, in theory, this should optimize performance, or maybe not...
Is it better to let the script get to the end or die() will actually speed up the process? If die() has negative consequences, of course, there are other ways around it, like creating flags to let the script skip certain chunks of code, I just want to know the negative effects of die() if any.
For example:
- In terms of memory, will die() keep using memory or maybe it frees up more memory.
- In terms of time/execution will die() speed up a process because it will not try to execute the rest of the script, or it makes no difference at all. Imagine that down the code there might be a heavy process that can be avoided.
I want to be clear about this, I know there must be many other ways to be more efficient, shorter scripts, switches, flags, etc. I just want to understand if there is any negative impact of using die().
Thanks
The usage of die/exit is a sign of poor code design and it would eventually lead to buggy code. In that sense, it would have negative impact. When exit runs, it terminates the script execution after calling the shutdown function (if shutdown
callback function is registered). The only time die/exit produces a positive output if it is used with 0(zero) which terminates the script execution successfully. All the other occurences point to errors. As a result, there is no need to use exit.
Frankly, I should add that if the answer is using exit/die, then either the question is wrong or the script is poorly written. In your example, if a script needs to run depending on a value, then the code should be something like:
abstract class AbstractProcess {
abstract public function run();
}
class A extends AbstractProcess {
public function run() { echo 'A'; }
}
class B extends AbstractProcess {
public function run() { echo 'B'; }
}
class C extends AbstractProcess {
public function run() { echo 'C'; }
}
class ProcessException extends \Exception { }
class Processor
{
private $handlers = [];
public function addProcess($key, AbstractProcess $process)
{
$this->handlers[$key] = $process;
}
public function run($val)
{
if ( !isset($this->handlers[$val]) )
{
throw new ProcessException('Cannot process value: ' . $val);
}
return $this->handlers[$val]->run();
}
}
This can be more sophisticated. That's not the point. It comes down to having a good exception handling policy. There are hundereds of resources you can find online about Exceptions and how to implement exception handling. Most of the modern frameworks have this built in - all you need is to introduce your exception handling logic. We run the above code in a try/catch block and handle the exception:
try {
$processor = new Processor();
$processor->addProcess('a', new A());
$processor->addProcess('b', new B());
$processor->addProcess('c', new C());
$processor->run('5');
} catch ( \Exception $e) {
if ( $e instanceof ErrorException ) {
// handle error exception
}
if ( $e instanceof ProcessException ) {
echo $e->getMessage();
}
// ..
}
Now, if we exited rather than handling the Exception, then we would be introducing a bug that can be very difficult to find. We may not be even aware of such an 'exit' if the script is running in the background.

Aborting and resuming a Symfony Console command

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.

Right strategy with shared memory and semaphore removing in RAII like php class

When such situation occurs?
If your are using shared memory and semaphores for interpocess locking (with pcntl extension) you should care about semaphore and shared memory segment life circle. For example, you writing backgroud worker application and use master and some child (forked) process for job processing. Using shared memory and semaphores good idea for IPC between them. And RAII like class wrapper around shm_xxx and sem_xxx php functions look`s like good idea too.
Example
class Semaphore
{
private $file;
private $sem;
public function __construct()
{
$this->file = tempnam(sys_get_temp_dir(), 's');
$semKey = ftok($this->file, 'a');
$this->sem = sem_get($semKey, 1); //auto_release = 1 by default
}
public function __destruct()
{
if (is_resource($this->sem) {
sem_remove($this->sem);
}
}
....
}
Not the good choise - after fork we have one instanse in parent and one in child process. And destructor in any of them destroy the semaphore.
Why important
Most of linux systems has limit about semaphore of shared memory count. If you have application which should create and remove many shared memory segfments of semaphores you can`t wait while it be automatically released on process shutdown.
Question
Using с you can use shmctl with IPC_RMID - it marks the segment for removal. The actual removal itself occurs when the last process currently attached to the segment has properly detached it. Of course, if no processes are currently attached to the segment, the removal seems immediate. It works like simple referenc counter. But php do not implements shmctl.
The other strategy - destroy semaphore only in destructor of master process:
class Semaphore
{
...
private $pid;
public function __construct()
{
$this->pid = getmypid();
...
}
public function __destruct()
{
if (is_resource($this->sem) && $this->pid === getmypid()) {
sem_remove($this->sem);
}
}
....
}
So, the questions is
If any way to use IPC_RMID in php?
What strategy should be used in such cases? Destroy in master process only? Other cases?
I checked the current PHP source code and IPC_RMID is not used. However, PHP uses semop() and with it, the SEM_UNDO flag, in case auto_release (see PHP sem_get() manual) is set. But be aware that this works on a per process level. So in case you are using PHP as Apache module, or FCGI or FPM, it might not work as expected. It should work nicely for CLI, though.
For your cleanup, it depends on whether the "master" terminates last or not.
If you do not know, you can implement reference counting yourself.
class Semaphore
{
static private $m_referenceCount = 0;
public function __construct()
{
++self::$m_referenceCount;
// aquire semaphore
}
public function __destruct()
{
if (--self::$m_referenceCount <= 0) {
// clean up
}
}
}
But be aware that the destructor is NOT executed in some circuumstances.

PHP - Troubles using pcntl_fork with shutdown function

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");

How do you use PHPUnit to test a function if that function is supposed to kill PHP?

Essentially I have a method of a class called killProgram, which is intended to send a hTTP redirect and then kill PHP.
How am I supposed to test this? When I run phpunit it doesn't return anything for that test, and closes completely.
Right now I'm considering having the killProgram function throw an exception which shouldn't get handled, which would allow me to assert that an exception was thrown.
Is there a better way?
It's obviously an old question but my suggestion would be to move the code that die()'s into a separate method that you can then mock.
As an example, instead of having this:
class SomeClass
{
public function do()
{
exit(1);
// or
die('Message');
}
}
do this:
class SomeClass
{
public function do()
{
$this->terminate(123);
// or
$this->terminate('Message');
}
protected function terminate($code = 0)
{
exit($code);
}
// or
protected function terminate($message = '')
{
die($message);
}
}
That way you can easily mock the terminate method and you don't have to worry about the script terminating without you being able to catch it.
Your test would look something like this:
class SomeClassTest extends \PHPUnit_Framework_TestCase
{
/**
* #expectedExceptionCode 123
*/
public function testDoFail()
{
$mock = $this->getMock('SomeClass');
$mock->expects($this->any())
->method('terminate')
->will($this->returnCallback(function($code) {
throw new \Exception($code);
}));
// run to fail
$mock->do();
}
}
I haven't tested the code but should be pretty close to a working state.
As every tests are run by the same PHPUnit process, if you use exit/die in your PHP code, you will kill everything -- as you noticed ^^
So, you have to find another solution, yes -- like returning instead of dying ; or throwing an exception (you can test if some tested code has thrown an expected exception).
Maybe PHPUnit 3.4 and it's --process-isolation switch (see Optionally execute each test using a separate PHP process) might help (by not having everything dying), but you still wouldn't be able to get the result of the test, if PHPUnit doesn't get the control back.
I've had this problem a couple of times ; solved it by returning instead of dying -- even returning several times, if needed, to go back "high enough" in the call stack ^^
In the end, I suppose I don't have any "die" anymore in my application... It's probably better, when thinking about MVC, btw.
There's no need to change the code just to be able to test it, you can simply use set_exit_overload() (provided by test_helpers from same author as PHPUnit).
I realise you've already accepted an answer for this and it's an old question, but I figure this might be useful for someone, so here goes:
Instead of using die(), you could use throw new RuntimeException() (or an exception class of your own), which will also halt program execution (albeit in a different fashion) and use PHPUnit's setExpectedException() to catch it. If you want your script to die() when that exception is encountered, printing absolutely nothing up at level of the user, take a look at set_exception_handler().
Specifically, I'm thinking of a scenario in which you'd place the set_exception_handler()-call into a bootstrap file that the tests don't use, so the handler won't fire there regardless of scenario, so nothing interferes with PHPUnit's native exception handling.
This relates to set of issues I've been having getting some legacy code to pass a test. So I've come up with a Testable class like this...
class Testable {
static function exitphp() {
if (defined('UNIT_TESTING')) {
throw new TestingPhpExitException();
} else {
exit();
}
}
}
Now I simply replace calls to exit() with Testable::exitphp().
If it's under test I just define UNIT_TESTING, in production I don't. Seems like a simple Mock.
You can kill the script or throw an exception, depending on the value of an environmental variable...
So you kill in production or throw an exception in test environment.
Any call to die or exit, Kills the whole process...
This was supposed to be a comment but I can't comment with the level of my reputation points.

Categories