NotionCommotion Posted December 13, 2020 Share Posted December 13, 2020 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(); Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/ Share on other sites More sharing options...
requinix Posted December 13, 2020 Share Posted December 13, 2020 (edited) 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 December 14, 2020 by requinix Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/#findComment-1583020 Share on other sites More sharing options...
NotionCommotion Posted December 14, 2020 Author Share Posted December 14, 2020 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) Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/#findComment-1583053 Share on other sites More sharing options...
requinix Posted December 14, 2020 Share Posted December 14, 2020 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. Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/#findComment-1583068 Share on other sites More sharing options...
NotionCommotion Posted December 14, 2020 Author Share Posted December 14, 2020 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. Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/#findComment-1583072 Share on other sites More sharing options...
requinix Posted December 14, 2020 Share Posted December 14, 2020 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. Quote Link to comment https://forums.phpfreaks.com/topic/311855-does-the-destructor-work-when-running-on-the-command-line-or-as-a-service/#findComment-1583077 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.