You can go to /etc/init. d/ - you will see a daemon template called skeleton. You can duplicate it and then enter your script under the start function. you may also consider running the script in background by adding '&' at the end or running it with nohup.
Daemons are special applications that can monitor and process an important activity on a machine in the background.
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.
Another option is to use Upstart. It was originally developed for Ubuntu (and comes packaged with it by default), but is intended to be suitable for all Linux distros.
This approach is similar to Supervisord and daemontools, in that it automatically starts the daemon on system boot and respawns on script completion.
Create a new script file at /etc/init/myphpworker.conf
. Here is an example:
# Info
description "My PHP Worker"
author "Jonathan"
# Events
start on startup
stop on shutdown
# Automatically respawn
respawn
respawn limit 20 5
# Run the script!
# Note, in this example, if your PHP script returns
# the string "ERROR", the daemon will stop itself.
script
[ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; )
end script
sudo service myphpworker start
sudo service myphpworker stop
sudo service myphpworker status
A big thanks to Kevin van Zonneveld, where I learned this technique from.
With new systemd you can create a service.
You must create a file or a symlink in /etc/systemd/system/
, eg. myphpdaemon.service and place content like this one, myphpdaemon will be the name of the service:
[Unit]
Description=My PHP Daemon Service
#May your script needs MySQL or other services to run, eg. MySQL Memcached
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service
[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/myphpdaemon.pid
ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null
#ExecStop=/bin/kill -HUP $MAINPID #It's the default you can change whats happens on stop command
#ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all php output to this one.
StandardError=/var/log/myphpdaemon.log
[Install]
WantedBy=default.target
You will be able to start, get status, restart and stop the services using the command
systemctl <start|status|restart|stop|enable> myphpdaemon
The PHP script should have a kind of "loop" to continue running.
<?php
gc_enable();//
while (!connection_aborted() || PHP_SAPI == "cli") {
//Code Logic
//sleep and usleep could be useful
if (PHP_SAPI == "cli") {
if (rand(5, 100) % 5 == 0) {
gc_collect_cycles(); //Forces collection of any existing garbage cycles
}
}
}
Working example:
[Unit]
Description=PHP APP Sync Service
Requires=mysqld.service memcached.service
After=mysqld.service memcached.service
[Service]
User=root
Type=simple
TimeoutSec=0
PIDFile=/var/run/php_app_sync.pid
ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php 2>&1 > /var/log/app_sync.log'
KillMode=mixed
Restart=on-failure
RestartSec=42s
[Install]
WantedBy=default.target
If your PHP routine should be executed once in a cycle (like a diggest) you may should use a shell or bash script to be invoked into systemd service file instead of PHP directly, for example:
#!/usr/bin/env bash
script_path="/app/services/"
while [ : ]
do
# clear
php -f "$script_path"${1}".php" fixedparameter ${2} > /dev/null 2>/dev/null
sleep 1
done
If you chose these option you should change the KillMode to mixed
to processes, bash(main) and PHP(child) be killed.
ExecStart=/app/phpservice/runner.sh phpfile parameter > /dev/null 2>/dev/null
KillMode=process
This method also is effective if you're facing a memory leak.
Note: Every time that you change your "myphpdaemon.service" you must run `systemctl daemon-reload', but do worry if you not do, it will be alerted when is needed.
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:
umask(0)
to prevent permission issues.fork()
and have the parent exit.setsid()
.SIGHUP
(usually this is ignored or used to signal the daemon to reload its configuration) and SIGTERM
(to tell the process to exit gracefully).fork()
again and have the parent exit.chdir()
.fclose()
stdin
, stdout
and stderr
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 :).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.
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 daemontools 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.
You can
nohup
as Henrik suggested.screen
and run your PHP program as a regular process inside that. This gives you more control than using nohup
. I'd recommend the simplest method (screen in my opinion) and then if you want more features or functionality, move to more complex methods.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With