I need to run a php script as daemon process (wait for instructions and do stuff). cron job will not do it for me because actions need to be taken as soon as instruction arrives. I know PHP is not really the best option for daemon processes due to memory management issues, but due to various reasons I have to use PHP in this case. I came across a tool by libslack called Daemon (http://libslack.org/daemon) it seems to help me manage daemon processes, but there hasn't been any updates in the last 5 years, so I wonder if you know some other alternatives suitable for my case. Any information will be really appreciated.
You could start your php script from the command line (i.e. bash) by using
nohup php myscript.php &
the &
puts your process in the background.
Edit:
Yes, there are some drawbacks, but not possible to control? That's just wrong.
A simple kill processid
will stop it. And it's still the best and simplest solution.
If you can - grab a copy of Advanced Programming in the UNIX Environment. The entire chapter 13 is devoted to daemon programming. Examples are in C, but all the function you need have wrappers in PHP (basically the pcntl and posix extensions).
In a few words - writing a daemon (this is posible only on *nix based OS-es - Windows uses services) is like this:
- Call
umask(0)
to prevent permission issues. fork()
and have the parent exit.- Call
setsid()
. - Setup signal processing of
SIGHUP
(usually this is ignored or used to signal the daemon to reload its configuration) andSIGTERM
(to tell the process to exit gracefully). fork()
again and have the parent exit.- Change the current working dir with
chdir()
. fclose()
stdin
,stdout
andstderr
and don't write to them. The corrrect way is to redirect those to either/dev/null
or a file, but I couldn't find a way to do it in PHP. It is possible when you launch the daemon to redirect them using the shell (you'll have to find out yourself how to do that, I don't know :).- Do your work!
Also, since you are using PHP, be careful for cyclic references, since the PHP garbage collector, prior to PHP 5.3, has no way of collecting those references and the process will memory leak, until it eventually crashes.
Kevin van Zonneveld wrote a very nice detailed article on this, in his example he makes use of the System_Daemon
PEAR package (last release date on 2009-09-02).
There is more than one way to solve this problem.
I do not know the specifics but perhaps there is another way to trigger the PHP process. For instance if you need the code to run based on events in a SQL database you could setup a trigger to execute your script. This is really easy to do under PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html .
Honestly I think your best bet is to create a Damon process using nohup. nohup allows the command to continue to execute even after the user has logged out:
nohup php myscript.php &
There is however a very serious problem. As you said PHP's memory manager is complete garbage, it was built with the assumption that a script is only executing for a few seconds and then exists. Your PHP script will start to use GIGABYTES of memory after only a few days. You MUST ALSO create a cron script that runs every 12 or maybe 24 hours that kills and re-spawns your php script like this:
killall -3 php
nohup php myscript.php &
But what if the script was in the middle of a job? Well kill -3 is an interrupt, its the same as doing a ctrl+c on the CLI. Your php script can catch this interrupt can exit gracefully using the PHP pcntl library: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php
Here is an example:
function clean_up() {
GLOBAL $lock;
mysql_close();
fclose($lock)
exit();
}
pcntl_signal(SIGINT, 'clean_up');
The idea behind the $lock is that the PHP script can open a file with a fopen("file","w");. Only one process can have a write lock on a file, so using this you can make sure that only one copy of your PHP script is running.
Good Luck!
I run a large number of PHP daemons.
I agree with you that PHP is not the best (or even a good) language for doing this, but the daemons share code with the web-facing components so overall it is a good solution for us.
We use dameontools for this. It is smart, clean and reliable. In fact we use it for running all of our daemons.
You can check this out at http://cr.yp.to/daemontools.html.
EDIT: A quick list of features.
- Automatically starts the daemon on reboot
- Automatically restart dameon on failure
- Logging is handled for you, including rollover and pruning
- Management interface: 'svc' and 'svstat'
- UNIX friendly (not a plus for everyone perhaps)
You can
- Use
nohup
as Henrik suggested. - Use
screen
and run your PHP program as a regular process inside that. This gives you more control than usingnohup
. - Use a daemoniser like http://supervisord.org/ (it's written in Python but can daemonise any command line program and give you a remote control to manage it).
- Write your own daemonise wrapper like Emil suggested but it's overkill IMO.
I'd recommend the simplest method (screen in my opinion) and then if you want more features or functionality, move to more complex methods.