Sending a synchronous signal/message to a long running PHP script - php

I have a long running PHP script that I'm attempting to convert into a systemd daemon.
While planing the daemon, I figured that I could simply send SITERM/SIGUSR1/SIGUSR2/etc. signals to restart/reload to my script when necessary using the kill command, but after reading through the systemd documentation, I've noticed this bit in the "ExecReload" section:
Note however that reloading a daemon by sending a signal (as with the example line above) is usually not a good choice, because this is an asynchronous operation and hence not suitable to order reloads of multiple services against each other. It is strongly recommended to set ExecReload= to a command that not only triggers a configuration reload of the daemon, but also synchronously waits for it to complete.
So, while my script will run just fine and the daemon itself will work properly using kill to signal various events (I don't have and most likely won't ever have another daemon that would depend on this one), the quote above got me thinking about alternatives of sending a synchronous message to the daemon.
The only thing that I could think of so far is:
Open a local socket in the daemon and listen for messages on it
Execute any supported action when receiving a message
Send an OK message back to the sender once the action is complete
Is there a better/recommended/optimal way of achieving this?

Related

ReactPHP: Running server with start/stop commands

i'm creating a socket server with ReactPHP and i need it to run forever.
I also have a command panel where i have to check if the process is running, and i can stop or start it (or restart it).
I don't know howe to achieve this.
My plan was:
With play button: start the php command shell_exec with simply "php script.php".
With stop button i can do in 2 ways: 1. i can set in the loop a timer that every 5 seconds checks if there is file inside the folder (like "stop.lock") and then stop the process. 2. i can save the process PID in the database, and so clicking the stop button i can just kill the process.
Checking online status: I can make another script that tries to connect to the IP/port and if succeeds is online, if not (timeout 5 seconds) is offline.
I also want the script stay always in the listening status, so how can i make the script auto-start if for example i have to restart my server?
I was thinking about a cron trying to connect to the server every minutes; and if it fails, it will just lauch again shell_exec('php script.php');
How is the best solution to handle all? (Server OS is CentOS 7)
As #Volker said, just stop the loop if you want to stop it gracefully. You could check periodically a file or query a table but that's not a great way.
A nice flow could be to listen to an admin message to stop the server. Of course, you should care of authenticating who can stop the server. This way it will stop without having to wait an interval to run, and you reduce the overhead of querying periodically your filesystem or your database.
Another cool way could be using RabbitMQ or a similar queue service. You just listen to your queue server, and you can send a message from your script to RabbitMQ, and from there to your server.
Good luck!
Edit: If you are running your server with systemd, a great way of handling it could be just to listen to a system signal to gracefully stop the application. Take a look at addSignal, you can handle a kill by pid, but also through systemd.
To handle graceful shutdown versus long running streamed response I've created a acquire/release like mechanism.
When a handler starts streaming a long response it acquires a lock and when streaming is done it releases it (it's just an array of uniqid()).
The server can decide to wait if there is active locks.
I use supervisor to handle the start/stop with a SIGTERM signal.

Sending signals to a process opened by proc_open()

We've got a utility here that's using proc_open() to call ssh to run commands on a remote machine. However, in some cases we need to halt the command on the remote machine but proc_close() and proc_terminate() do not cause the desired signal to be sent through to the far side of the ssh connection. SSH will generally issue a SIGHUP to running programs when it is terminated, but we need to send a SIGINT to ssh which will forward it through to the program running on the remote end.
I've googled as much as I can, and there seem to be a number of pcntl functions for receiving signals, but I have not been able to find anything about sending signals via PHP, let alone anything related to proc_* functions.
You can sending signals via PHP :
posix_kill(posix_getpid(), SIGTERM);

Persistent PHP socket server

I'm planning the development of a server written in PHP that can service socket requests. I use a free host (Heliohost) for testing, and it has cPanel. So far the only thing I've been able to think of to have a PHP script always running is to write a cron job that runs a bash script to check ps to see if the PHP is already running, and if it isn't, start it.
Is there a better way? Perhaps a way for a PHP thread to be started on an HTTP request and continue to run in Apache after the request has been serviced?
You will almost certainly not have success running persistent processes from Apache. It is designed to prevent that scenario (though if you can get to the fork(2) system call, it is probably do-able). I wouldn't recommend trying it though.
What would make more sense is if you use a hosting provider that gives you the ability to write your own crontab(5) specifications and run the PHP interpreter directly. Then you could just add a line to your crontab(5) like:
#reboot /path/to/php /path/to/script.php
Your script should probably perform the usual daemonization tasks so that cron(8) isn't stuck waiting for your process to exit.

system daemon pear

Question,
How can I spurn another process within a daemon?
I want to use the pear system daemon library to spurn a daemon and then spurn off processes within that daemon.
So daemon runs
and then a new process is spurn off and does calculation separately
then other processes are spurn off that runs separate from the daemon.
meanwhile, daemon keeps executing code and spurns off more processes
how can I accomplish this?
System_Daemon only handles startup/shutdown handling, general signal handling and logging.
If you want to spawn new processes from your PHP code, you need to use PHP's pcntl functions.
Spurn? I assume you mean spawn.
PHP has lots of functions for creating processes - however (AFAIK) they are all blocking (except for pcntl_exec which replaces the current process)
A quick sift through the documentation for the Pear System Daemon, this only handles the process of daemonizing the process - not of running a server process and handling multiple clients. How you go about implementing this will have a big impact on how you handle starting up new processes.
One solution would be to fork an instance of the current process to handle an incoming connection - there's an example on the socket_accept() doc page. Then it doesn't matter if the process you start is via a blocking call or not.
But a much simlper solution would be not to bother with a daemon / forking / sockets and just invoke it via [x]inetd using stdio
C.
I had the same problem before. The solution I did was to have one system_daemon calling another system_daemon through exec. You need to change the appPidLocation option to run a new instance of the same code.
To see the list of options I looked at the code of system_daemon.

Checking the status of my PHP beanstalkd background processes

I have a website written in PHP (CakePHP) where certain resource intensive tasks are handled by a background process. This is done through the Beanstalkd message queue. I need some way to retrieve the status of that background process so I can monitor it with Monit.
The background process is a CakePHP Shell (just a PHP CLI script) that communicates with Beanstalkd. It simply does a reserve() on Benastalkd and waits for a new message. When it gets a message, it processes it. I want some way of monitoring this process with Monit so that it can restart the background process if something has gone wrong.
What I have been thinking about so far is writing a PHP CLI script that drops a message in Beanstalkd. The background process picks up the message and somehow communicates it's internal status back to the CLI script. But how? Sockets? Shared memory? Some other IPC method?
Or am I perhaps being too complicated here and is there a much easier way to monitor such a process with Monit?
Thanks in advance!
Here's what I ended up doing in the end.
The CLI script connects to beanstalkd, creates a new queue (tube) and starts watching it. Then it drops a highest priority message in the queue that the background daemon is watching. That message contains the name of the new queue that the CLI script is monitoring.
The background process receives this message almost immediately (because it is highest priority), generates a status message and puts it in the queue that the CLI script is watching. The CLI script receives it and then closes the queue.
When the CLI script does not get a response in 30 seconds it will exit with an error indicating the background daemon is (most likely) hung.
I tied all this into Monit. Monit can now check that the background daemon is running (via the pidfile and process list) and verify that it is actually still processing messages (by using the CLI tool to test that it responds to status requests)
There probably is a plugin to Monit or Nagios to connect, run the stats and return if there are 'too many'. There isn't a 'protocol' written already for that, but t doesn't appear to be exceeding difficult to modify an existing text-based one (like nntp, or smtp) to do what you want. It does mean writing it in C though, by the looks of it.
From a CLI-PHP script, I would go about it through one (or both) of two different methods.
1/ drop a (low-ish) priority message into the queue, and make sure it comes back within a few seconds. Putting it into a dedicated queue and making sure there's nothing there before you put it in there would be a good addition as well.
2/ perform a 'stats' and see how many are waiting: 'current-jobs-ready'.
To get the information back to a website (either way), you can write to a file, or into something like Memcached which gts read and acted upon.

Categories