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)

 

3 hours ago, NotionCommotion said:

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

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

3 hours ago, 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);

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.

3 hours ago, NotionCommotion said:

How should the process be stopped?

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

3 hours ago, NotionCommotion said:

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

Try without and see what happens.

43 minutes ago, 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.

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

45 minutes ago, 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.

Will do.

45 minutes ago, requinix said:

Try without and see what happens.

Did so and no difference that I could determine.

41 minutes ago, NotionCommotion said:

Did so and no difference that I could determine.

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.