Jump to content

Does the destructor work when running on the command line or as a service


Recommended Posts

I would like to update the DB when a service ends and thought about doing so in the destructor, but I did not make much progress.  Then tried using pcntl_signal(), but also didn't get far.  Is doing so possible?  Thanks

/usr/lib/systemd/system/test123.service

[Unit]
Description=bla
After=syslog.target

[Service]
ExecStart=/usr/bin/php /var/www/testing/__destruct.php

[Install]
WantedBy=multi-user.target

 

/var/www/testing/__destruct.php

<?php
ini_set('display_errors', 1);

pcntl_signal(SIGTERM, function() {
    syslog(LOG_INFO, 'Caught SIGTERM');
    die;
});
pcntl_signal(SIGHUP, function() {
    syslog(LOG_INFO, 'Caught SIGHUP');
    die;
});
pcntl_signal(SIGUSR1, function() {
    syslog(LOG_INFO, 'Caught SIGUSR1');
    die;
});
pcntl_signal(SIGINT, function() {
    syslog(LOG_INFO, 'Caught SIGINT');
    die;
});
pcntl_signal(SIGABRT , function() {
    syslog(LOG_INFO, 'Caught SIGABRT ');
    die;
});
/*
pcntl_signal(SIGSTOP , function() {
    syslog(LOG_INFO, 'Caught SIGSTOP ');
    die;
});
*/
/*
pcntl_signal(SIGKILL , function() {
    syslog(LOG_INFO, 'Caught SIGKILL ');
    die;
});
*/

class Bla
{
    private $bla;
    public function __construct($bla) {
        syslog(LOG_INFO, '__construct');
        $this->bla = $bla;
    }

    public function __destruct()
    {
        syslog(LOG_INFO, '__destruct');
    }

    public function start()
    {
        $counter=0;
        $counter2=0;
        while(true) {
            $counter++;
            if($counter>10000000) {
                $counter2++;
                $counter=0;
                syslog(LOG_INFO, '.');
            }
            if($counter2>5) {
                die('all done!');
            }
        }
    }

}

$bla = new Bla('hello');
$bla->start();

 

Destructors are about cleaning up resources used by the class and are not suitable as some sort of "shutdown" event. They're tied to variable and memory usage, not script execution.

If you want to run some code when the service is shutting down then do exactly that: set up signal handlers as needed to allow your code to terminate gracefully, and/or use register_shutdown_function().

For example,

<?php

pcntl_async_signals(true);

$running = true;
pcntl_signal(SIGINT, function() use (&$running) {
	echo "Caught ^C\n";
	$running = false;
});

while ($running) {
	echo ".";
	sleep(1) && pcntl_signal_dispatch();
}

(if you had problems catching signals then it's likely you were missing pcntl_async_signals)

edit: ^C is SIGINT, not SIGTERM

Edited by requinix

I've never dealt with signals before, or more accurately I likely have done so but didn't know I was doing so.  Interesting use cases!  When I was messing around with this yesterday, got a little worried about my program going rouge and had to kill the process from the command line.  Below is the PHP script, my systemctl service, actions I performed, and journalctl output.   I have a few questions included in the PHP script as comments and would appreciate your thoughts.  Thanks

<?php
ini_set('display_errors', 1);

declare(ticks = 1); //Maybe do less often to improve performance because quick response is not necessary?

//The following has no affect.  phpinfo shows zend.signal_check off and Zend Signal Handling enabled.  Need I call it?
//pcntl_async_signals(true);

pcntl_signal(SIGTERM, function() {
    $pid = getmypid();
    echo "received SIGTERM.  Update DB and kill process $pid\n";
    //updateDatabase();
    //How should the process be stopped?  While it works, journalctl shows "failed state.."  Also, do I care about "Unregistered Authentication Agent" in journalctl?
    posix_kill($pid, SIGKILL);
});

// Below script is for testing only and will be replaced with a reactphp loop
$x = 0;
while (true) {
    echo ".";
    sleep(1);
    //sleep(1) && pcntl_signal_dispatch(); // pcntl_signal_dispatch — Calls signal handlers for pending signals.  Why call it?
    if ($x >= 10) {
        posix_kill($pid, SIGKILL);
    }
    ++$x;
}

$ cat /usr/lib/systemd/system/pcntl_async_signals.service

[Unit]
Description=my_pcntl_async_signals
After=syslog.target

[Service]
ExecStart=/usr/bin/php /var/www/testing/pcntl_async_signals.php

[Install]
WantedBy=multi-user.target

 

$ sudo systemctl start pcntl_async_signals.service
$ sudo systemctl stop pcntl_async_signals.service

 

Dec 14 14:04:20 devserver sudo[27683]:  michael : TTY=pts/0 ; PWD=/var/www/testing ; USER=root ; COMMAND=/bin/systemctl start pcntl_async_signals.service
Dec 14 14:04:20 devserver sudo[27683]: pam_unix(sudo:session): session opened for user root by michael(uid=0)
Dec 14 14:04:20 devserver polkitd[766]: Registered Authentication Agent for unix-process:27684:8411203 (system bus name :1.322 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)
Dec 14 14:04:20 devserver systemd[1]: Started my_pcntl_async_signals.
Dec 14 14:04:20 devserver sudo[27683]: pam_unix(sudo:session): session closed for user root
Dec 14 14:04:20 devserver polkitd[766]: Unregistered Authentication Agent for unix-process:27684:8411203 (system bus name :1.322, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8) (disconnected from bus)
Dec 14 14:04:26 devserver influxd[1145]: [httpd] 127.0.0.1 - - [14/Dec/2020:14:04:26 +0000] "POST /write?db=greenbean&precision=s HTTP/1.1" 204 0 "-" "GuzzleHttp/6.5.5 curl/7.29.0 PHP/7.4.12" 46a1b0c0-3e15-11eb-9cdd-0050563b3f69 3262
Dec 14 14:04:26 devserver sudo[27691]:  michael : TTY=pts/0 ; PWD=/var/www/testing ; USER=root ; COMMAND=/bin/systemctl stop pcntl_async_signals.service
Dec 14 14:04:26 devserver sudo[27691]: pam_unix(sudo:session): session opened for user root by michael(uid=0)
Dec 14 14:04:26 devserver polkitd[766]: Registered Authentication Agent for unix-process:27692:8411859 (system bus name :1.324 [/usr/bin/pkttyagent --notify-fd 5 --fallback], object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8)
Dec 14 14:04:26 devserver systemd[1]: Stopping my_pcntl_async_signals...
Dec 14 14:04:26 devserver php[27690]: .......received SIGTERM.  Update DB and kill process 27690
Dec 14 14:04:26 devserver systemd[1]: pcntl_async_signals.service: main process exited, code=killed, status=9/KILL
Dec 14 14:04:26 devserver systemd[1]: Stopped my_pcntl_async_signals.
Dec 14 14:04:26 devserver systemd[1]: Unit pcntl_async_signals.service entered failed state.
Dec 14 14:04:26 devserver systemd[1]: pcntl_async_signals.service failed.
Dec 14 14:04:26 devserver sudo[27691]: pam_unix(sudo:session): session closed for user root
Dec 14 14:04:26 devserver polkitd[766]: Unregistered Authentication Agent for unix-process:27692:8411859 (system bus name :1.324, object path /org/freedesktop/PolicyKit1/AuthenticationAgent, locale en_US.UTF-8) (disconnected from bus)

 

  On 12/14/2020 at 2:21 PM, NotionCommotion said:

declare(ticks = 1); //Maybe do less often to improve performance because quick response is not necessary?

Expand  

Don't do at all. ticks are old and fragile when it comes to signal handling. Use pcntl_async_signals like I posted.

  On 12/14/2020 at 2:21 PM, NotionCommotion said:

//The following has no affect.  phpinfo shows zend.signal_check off and Zend Signal Handling enabled.  Need I call it?
//pcntl_async_signals(true);

Expand  

It will matter when you stop using ticks.

If you don't know what zend.signal_check does then read the docs. Don't just guess at what it means.

  On 12/14/2020 at 2:21 PM, NotionCommotion said:

How should the process be stopped?

Expand  

Stop what you're doing and learn about systemd services.

  On 12/14/2020 at 2:21 PM, NotionCommotion said:

// pcntl_signal_dispatch — Calls signal handlers for pending signals.  Why call it?

Expand  

Try without and see what happens.

  On 12/14/2020 at 6:16 PM, requinix said:

Don't do at all. ticks are old and fragile when it comes to signal handling. Use pcntl_async_signals like I posted.

It will matter when you stop using ticks.

Expand  

10-4.  Without doing so, pcntl_signal doesn't catch the SIGTERM signal.

  On 12/14/2020 at 6:16 PM, requinix said:

If you don't know what zend.signal_check does then read the docs. Don't just guess at what it means.

Stop what you're doing and learn about systemd services.

Expand  

Will do.

  On 12/14/2020 at 6:16 PM, requinix said:

Try without and see what happens.

Expand  

Did so and no difference that I could determine.

  On 12/14/2020 at 7:03 PM, NotionCommotion said:

Did so and no difference that I could determine.

Expand  

Increase the sleep time a bit, switch the signal handler to SIGINT (I was mistaken before about SIGTERM), then run and ^C it.

Or I may be out of date when it comes to signal dispatch. What I'm thinking of might not apply to async-dispatched signals.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.