» Create daemons in PHP

Everyone knows PHP can be used to create websites. But it can also be used to create desktop applications and commandline tools. And now with a class called System_Daemon, you can even create daemons using nothing but PHP. And did I mention it was easy?

What is a Daemon?

A daemon is a Linux program that run in the background, just like a 'Service' on Windows. It can perform all sorts of tasks that do not require direct user input. Apache is a daemon, so is MySQL. All you ever hear from them is found in somewhere in /var/log, yet they silently power over 40% of the Internet.

You reading this page, would not have been possible without them. So clearly: a daemon is a powerful thing, and can be bend to do a lot of different tasks.

Why PHP?

Most daemons are written in C. It's fast & robust. But if you are in a LAMP oriented company like me, and you need to create a lot of software in PHP anyway, it makes sense:

  • Reuse & connect existing code Think of database connections, classes that create customers from your CRM, etc.
  • Deliver new applications very fast PHP has a lot of build in functions that speed up development greatly.
  • Everyone knows PHP (right?) If you work in a small company: chances are there are more PHP programmers than there are C programmers. What if your C guy abandons ship? Admittedly it's a very pragmatic reason, but it's the same reason why Facebook is building HipHop.

Possible use cases

  • Website optimization If you're running a (large) website, jobs that do heavy lifting should be taken away from the user interface and scheduled to run on the machine separately.
  • Log parser Continually scan logfiles and import critical messages in your database.
  • SMS daemon Read a database queue, and let your little daemon interface with your SMS provider. If it fails, it can easily try again later!
  • Video converter (think Youtube) Scan a queue/directory for incoming video uploads. Make some system calls to ffmpeg to finally store them as Flash video files. Surely you don't want to convert video files right after the upload, blocking the user interface that long? No: the daemon will send the uploader a mail when the conversion is done, and proceed with the next scheduled upload

Deamons vs Cronjobs

Some people use cronjobs for the same Possible use cases. Crontab is fine but it only allows you to run a PHP file every minute or so.

  • What if the previous run hasn't finished yet? Overlap can seriously damage your data & cause siginificant load on your machines.
  • What if you can't afford to wait a minute for the cronjob to run? Maybe you need to trigger a process the moment a record is inserted?
  • What if you want to keep track of multiple 'runs' and store data in memory.
  • What if you need to keep your application listening (on a socket for example) Cronjobs are a bit rude for this, they may spin out of control and don't provide a

framework for logging, etc. Creating a daemon would offer more elegance & possibilities. Let's just say: there are very good reasons why a Linux OS isn't composed entirely of Cronjobs :)

How it works internally

(Nerd alert!) When a daemon program is started, it fires up a second child process, detaches it, and then the parent process dies. This is called forking. Because the parent process dies, it will give the console back and it will look like nothing has happened. But wait: the child process is still running. Even if you close your terminal, the child continues to run in memory, until it either stops, crashes or is killed.

In PHP: forking can be achieved by using the Process Control Extensions. Getting a good grip on it, may take some studying though.

System_Daemon

Because the Process Control Extensions' documentation is a bit rough, I decided to figure it out once, and then wrap my knowledge and the required code inside a PEAR class called: System_Daemon. And so now you can just:

require_once "System/Daemon.php";                 // Include the Class
 
System_Daemon::setOption("appName", "mydaemon");  // Minimum configuration
System_Daemon::start();                           // Spawn Deamon!

And that's all there is to it. The code after that, will run in your server's background. So next, if you create a while(true) loop around that code, the code will run indefinitely. Remember to build in a sleep(5) to ease up on system resources.

Features & Characteristics

Here's a grab of System_Daemon's features:

  • Daemonize any PHP-CLI script
  • Simple syntax
  • Driver based Operating System detection
  • Unix only
  • Additional features for Debian / Ubuntu based systems like:
  • Automatically generate startup files (init.d)
  • Support for PEAR's Log package
  • Can run with PEAR (more elegance & functionality) or without PEAR (for standalone packages)
  • Default signal handlers, but optionally reroute signals to your own handlers.
  • Set options like max RAM usage

Download

You could download the package from PEAR, or, if you have PEAR installed on your system: just run this from a console:

pear install -f System_Daemon

You can also update it using that last command.

Beta

Though I have quite some daemons set up this way, it's officially still beta. So please report any bugs over at the PEAR page. Other comments may be posted here.

Complex Example

Ready to dig a little deeper? This example program is called 'logparser', it takes a look at a more complex use of System_Daemon. For instance, it introduces command line arguments like:

--no-daemon              # just run the program in the console this time
--write-initd            # writes a startup file

Read this source to get the picture. Don't forget the comments!

#!/usr/bin/php -q
<?php
/**
 * System_Daemon turns PHP-CLI scripts into daemons.
 *
 * PHP version 5
 *
 * @category  System
 * @package   System_Daemon
 * @author    Kevin <kevin@vanzonneveld.net>
 * @copyright 2008 Kevin van Zonneveld
 * @license   http://www.opensource.org/licenses/bsd-license.php
 * @link      http://github.com/kvz/system_daemon
 */
 
/**
 * System_Daemon Example Code
 *
 * If you run this code successfully, a daemon will be spawned
 * but unless have already generated the init.d script, you have
 * no real way of killing it yet.
 *
 * In this case wait 3 runs, which is the maximum for this example.
 *
 *
 * In panic situations, you can always kill you daemon by typing
 *
 * killall -9 logparser.php
 * OR:
 * killall -9 php
 *
 */
 
// Allowed arguments & their defaults
$runmode = array(
    'no-daemon' => false,
    'help' => false,
    'write-initd' => false,
);
 
// Scan command line attributes for allowed arguments
foreach ($argv as $k=>$arg) {
    if (substr($arg, 0, 2) == '--' && isset($runmode[substr($arg, 2)])) {
        $runmode[substr($arg, 2)] = true;
    }
}
 
// Help mode. Shows allowed argumentents and quit directly
if ($runmode['help'] == true) {
    echo 'Usage: '.$argv[0].' [runmode]' . "\n";
    echo 'Available runmodes:' . "\n";
    foreach ($runmode as $runmod=>$val) {
        echo ' --'.$runmod . "\n";
    }
    die();
}
 
// Make it possible to test in source directory
// This is for PEAR developers only
ini_set('include_path', ini_get('include_path').':..');
 
// Include Class
error_reporting(E_STRICT);
require_once 'System/Daemon.php';
 
// Setup
$options = array(
    'appName' => 'logparser',
    'appDir' => dirname(__FILE__),
    'appDescription' => 'Parses vsftpd logfiles and stores them in MySQL',
    'authorName' => 'Kevin van Zonneveld',
    'authorEmail' => 'kevin@vanzonneveld.net',
    'sysMaxExecutionTime' => '0',
    'sysMaxInputTime' => '0',
    'sysMemoryLimit' => '1024M',
    'appRunAsGID' => 1000,
    'appRunAsUID' => 1000,
);
 
System_Daemon::setOptions($options);
 
// This program can also be run in the forground with runmode --no-daemon
if (!$runmode['no-daemon']) {
    // Spawn Daemon
    System_Daemon::start();
}
 
// With the runmode --write-initd, this program can automatically write a
// system startup file called: 'init.d'
// This will make sure your daemon will be started on reboot
if (!$runmode['write-initd']) {
    System_Daemon::info('not writing an init.d script this time');
} else {
    if (($initd_location = System_Daemon::writeAutoRun()) === false) {
        System_Daemon::notice('unable to write init.d script');
    } else {
        System_Daemon::info(
            'sucessfully written startup script: %s',
            $initd_location
        );
    }
}
 
// Run your code
// Here comes your own actual code
 
// This variable gives your own code the ability to breakdown the daemon:
$runningOkay = true;
 
// This variable keeps track of how many 'runs' or 'loops' your daemon has
// done so far. For example purposes, we're quitting on 3.
$cnt = 1;
 
// While checks on 3 things in this case:
// - That the Daemon Class hasn't reported it's dying
// - That your own code has been running Okay
// - That we're not executing more than 3 runs
while (!System_Daemon::isDying() && $runningOkay && $cnt <=3) {
    // What mode are we in?
    $mode = '"'.(System_Daemon::isInBackground() ? '' : 'non-' ).
        'daemon" mode';
 
    // Log something using the Daemon class's logging facility
    // Depending on runmode it will either end up:
    //  - In the /var/log/logparser.log
    //  - On screen (in case we're not a daemon yet)
    System_Daemon::info('{appName} running in %s %s/3',
        $mode,
        $cnt
    );
 
    // In the actuall logparser program, You could replace 'true'
    // With e.g. a  parseLog('vsftpd') function, and have it return
    // either true on success, or false on failure.
    $runningOkay = true;
    //$runningOkay = parseLog('vsftpd');
 
    // Should your parseLog('vsftpd') return false, then
    // the daemon is automatically shut down.
    // An extra log entry would be nice, we're using level 3,
    // which is critical.
    // Level 4 would be fatal and shuts down the daemon immediately,
    // which in this case is handled by the while condition.
    if (!$runningOkay) {
        System_Daemon::err('parseLog() produced an error, '.
            'so this will be my last run');
    }
 
    // Relax the system by sleeping for a little bit
    // iterate also clears statcache
    System_Daemon::iterate(2);
 
    $cnt++;
}
 
// Shut down the daemon nicely
// This is ignored if the class is actually running in the foreground
System_Daemon::stop();

Console action: Controlling the Daemon

Now that we've created an example daemon, it's time to fire it up! I'm going to assume the name of your daemon is logparser. This can be changed with the statement: System_Daemon::setOption('appName', 'logparser'). But the name of the daemon is very important because it is also used in filenames (like the logfile).

Execute

Just make your daemon script executable, and then execute it:

chmod a+x ./logparser.php
./logparser.php

Check

Your daemon has no way of communicating through your console, so check for messages in:

tail /var/log/logparser.log

And see if it's still running:

ps uf -C logparser.php

Kill

Without the start/stop files (see below for howto), you need to:

killall -9 logparser.php

Autch.. Let's work on those start / stop files, right?

Start / Stop files (Debian & Ubuntu only)

Real daemons have an init.d file. Remember you can restart Apache with the following statement?

/etc/init.d/apache2 restart

That's a lot better than killing. So you should be able to control your own daemon like this as well:

/etc/init.d/logparser stop
/etc/init.d/logparser start

Well with System_Daemon you can write autostartup files using the writeAutoRun() method, look:

$path = System_Daemon::writeAutoRun();

On success, this will return the path to the autostartup file: /etc/init.d/logparser, and you're good to go!

Run on boot

Surely you want your daemon to run at system boot.. So on Debian & Ubuntu you could type:

update-rc.d logparser defaults

Done your daemon now starts every time your server boots. Cancel it with:

update-rc.d -f logparser remove

Logrotate

Igor Feghali shares with us a logrotate config file to keep your log files from growing too large. Just place a file in your /etc/logrotate.d/.

/var/log/mydaemon.log {
   rotate 15
   compress
   missingok
   notifempty
   sharedscripts
   size 5M
   create 644 mydaemon_user mydaemon_group
   postrotate
       /bin/kill -HUP `cat /var/run/mydaemon/mydaemond.pid 2>/dev/null` 2> /dev/null || true
   endscript
}

Obviously, replace the mydaemon occurances with values corresponding to your environment. Thanks Igor!

Troubleshooting

Here are some issues you may encounter down the road.

  • Don't use echo() **Echo writes to the STDOUT of your current session. If you logout, that will cause fatal errors and the daemon to die. Use System_Daemon::log() instead.
  • Connect to MySQL after you start() the daemon. Otherwise only the parent process will have a MySQL connection, and since that dies.. It's lost and you will get a 'MySQL has gone away' error.
  • Error handling Good error handling is imperative. Daemons are often mission critical applications and you don't want an uncatched error to bring it to it's knees.
    • Reconnect to MySQL A connection may be interrupted. Think about network downtime or lock-ups when your database server makes backups. Whatever the cause: You don't want your daemon to die for this, let it try again later.
    • PHP error handler As of 0.6.3, System_Daemon forwards all PHP errors to the log() method, so keep an eye on your logfile. This behavior can be controlled using the logPhpErrors (true||false) option.
  • Monit Monit is a standalone program that can kickstart any daemon, based on your parameters. Should your daemon fail, monit will mail you and try to restart it.
  • Watch that memory Some classes keep a history of executed commands, sent mails, queries, whatever. They were designed without knowing they would ever be used in a daemonized environment. Cause daemons run indefinitely this 'history' will expand indefinitely. Since unfortunately your server's RAM is not infinite, you will run into problems at some point. This makes it's very important to address these memory 'leaks' when building daemons.
  • Statcache will corrupt your data If you do a file_exists(), PHP remembers the results to ease on your disk until the process end. That's ok but since the Daemon process does not end, PHP will not be able to give you up to date information. As of 0.8.0 you should call System_Daemon::iterate(2) instead of e.g. sleep(2), this will sleep & clear the cache and give you fresh & valid data.

I know I'm saying MySQL a lot, but you can obviously replace that with Oracle, MSSQL, PostgreSQL, etc.

You probably shouldn't follow me


Like this Article?

I'd appreciate it if you leave a comment, spread the word, or consider a small donation


tags: programming, php, daemon, PEAR
category: Programming - PHP - PEAR
read: 254,471 times

Add comment

(required, shown)(required, not shown)for syntax highlighting

[CODE="Javascript"]
your_code_here();
[/CODE]

Replace "Javascript"
with "php", "text", etc.
code (to make sure you are not a spammer)

 Track replies: rss feed comments feed

Comments

#261. ouiea on 17 January 2012

Gravatar.com: ouieaHi there, many thanks for this article!
I'm using Amazon's Linux (don't ask why) and I've been having the "No autoRunTemplateReplace found" when trying to create the init.d script.
In the end, I've ended editing the Daemon.php file
(located here in my install: /usr/share/pear/System ) and forcing RedHat as my OS:
search:

self::$_osObj = System_Daemon_OS::factory();

repace with:
self::$_osObj = System_Daemon_OS::factory('RedHat');

I could write the init.d file after that.

BTW, it would be great to have a bigger window for the comments, I feel like peeping through a keyhole ;)

Thanks!
H

#260. Pawel on 12 January 2012

Gravatar.com: PawelHi, Thanks for nice piece of software:)
Generally works fine, however I have some problem with my daemon.
Daemon was supposed to run some instructions every 3 seconds, but thanks to logs, I noticed that sometimes it freezes for around 1 hour.

So logs:
... [more] ...
[Jan 12 08:52:59] info: running
[Jan 12 08:53:02] info: running
[Jan 12 08:53:05] info: running
[Jan 12 10:06:26] info: running //waits over 1 hours instead of 3 seconds

The pause is done with: System_Daemon::iterate(3)

Wondering if anyone had similar problem, or has an idea what might be causing it ?

Thanks

#259. Tom on 10 January 2012

Gravatar.com: TomFor some reason iterate() was not waiting the proper amount of time. I still called it to clear the statcache but I also ended up using sleep() too. I said iterate(14400) and it instead continued in about 25 minutes (a few seconds off each loop). But this is really nice and really helped me a lot.

It's a LOT better than cron. I'm calling a command line script which calls a php file. Writing a script to call that and trigger on cron just was a nightmare because the script had to execute from a specific directory. So this was much better because you don't have to worry about the directory change being lost due to sub shells, etc.

Two other things worth mentioning are Gearman and Clockwork. Gearman is not going to be something you really want to loop and use like a daemon, but it's related and is nice. Clockwork is a replacement for cron basically. It's Ruby, but you should still be able to use PHP to control it. I haven't looked into it yet because it just took a few more minutes to setup than this and this worked perfect...But may be worth a look.

#258. Benji on 07 January 2012

Gravatar.com: BenjiMan alive, that's genius !

Thanks for sharing, you are a maven.

#257. Achim on 27 December 2011

Gravatar.com: AchimAnother big benefit of a daemon vs. a cron job, specially in PHP world, is the caching:

The APC op-code cache is basically useless in PHP-CLI environment. If a PHP will be called regularly via cron, the op-code will be compiled every time again, even APC don't persist the cache over several processes.
But in case of a daemon, the op-code will be compiled only once and used for each "loop" again and again - even if APC is not used :-)

#256. Ivang on 23 December 2011

Gravatar.com: IvangYou're the f*cking crack of the php standalone applications!
I was looking a way to avoid the (ethernal) use of cron and your post is the most useful article I found for months.

It probably gives some minor problem (like the previous comments) but it does not care, your little script for demonizing a php script is the best contribution to php since the MVC frameworks!!

... [more] Thank you very much

#255. Big Jim on 16 December 2011

Gravatar.com: Big JimThis runs great until I try to run it via a shell_exec call in a script like this:

shell_exec("/etc/init.d/logparser start");


It bizarrely loops through the script that makes the above call and gives this output 136 times:

X-Powered-By: PHP/5.3.8
 
Content-type: text/html


Followed by this 136 times:

Starting logparser:  [  OK  ]


It doesn't actually start the daemon though. I'm running this on CentOS w/ the following small modification for writing the start script:

$gid = 545;  // I've changed these, but they match the uid/gid to the script owner
$uid = 547;
 
if ($runmode['write-initd']) {
$gid = 0;
$uid = 0;
}
 
// Setup
$options = array(
'appName' => 'logparser',
'appDir' => dirname(__FILE__),
'appDescription' => 'Parses logfiles and stores them in MySQL',
'authorName' => 'Kevin van Zonneveld',
'authorEmail' => 'kevin@vanzonneveld.net',
'sysMaxExecutionTime' => '0',
'sysMaxInputTime' => '0',
'sysMemoryLimit' => '1024M',
'appRunAsGID' => $gid,
'appRunAsUID' => $uid,
);


I've also noticed that /etc/init.d/logparser status (and restart) don't work. I'm guessing something is wrong w/ the init.d start script, but I can't figure it out. Any ideas?

Thanks

#254. Carl on 09 December 2011

Gravatar.com: Carl...just wanted to add something to my previous comment...

If you get the "bash: chkconfig: command not found" and you already have it installed, just get it's location and run it from there:

[CODE=text"]
# whereis chkconfig
[/CODE]

I had to use:
[CODE=text"]
# /sbin/chkconfig --add myScript
[/CODE]

#253. Carl on 06 December 2011

Gravatar.com: Carl!! Attention CentOS users!!

Do the following if you want your daemon to run at system boot.

FYI: The following assumes that your script is called "logparser"

1.) Use your PHP script to write the autostartup files using the writeAutoRun() method.
!! Make sure "appRunAsGID" and "appRunAsUID" is set to 0 !!

2.) Add your script to the list of system services with:

# chkconfig --add logparser


3.) Don't forget to enable your service:
# chkconfig logparser on


That should be all there is to it :)

#252. Barney on 02 December 2011

Gravatar.com: BarneyWow, this is great! i looked at writing a daemon in C but couldn;t find alot of clear, reliable guides.

This has saved me a pile of work!

One problem though, on ubuntu (and i assume all debian systems) when i use the --write-initd parameter, i get a message in the log file that it wasn't possible to write to the /etc/init.d directory, and that i should try running as root.
... [more]
unfortunately i am already running as root!!!

any ideas?

#251. Roberto on 13 November 2011

Gravatar.com: RobertoGracias por el articulo del PHP Deamons, es mas que lo que necesitaba, quiero hacerte una donacion via paypal, pero donde ?

Saludos !!!

Hello Great job related to the PHP Deamons, I want to donate via paypal but where ?
... [more]
Best Regards !

#250. Iser Epstein on 04 November 2011

Gravatar.com: Iser EpsteinI run on Centos 6.0 and got the "--enable-pcntl" error.
Should I have to install other PHP Cli ?
If so,how to do that ? where can I get it from ?

#249. Jochem Stoel on 21 October 2011

Gravatar.com: Jochem StoelHello, thank you for this. This is making my world a little better. I use this for several things at the moment.

I came across a 'problem' with arguments given from the commandline. I will post the problem and my solution here in case it helps somebody.

Let's call your script daemon.php for the sake of it, you run the script by doing this:

./daemon.php


You can give arguments to your daemon by doing his:

./daemon.php --string hello --time 24


The array $argv then contains:
./daemon.php
--string
hello
--time
24


This daemon thing 'explodes' these arguments on a whitespace before they are passed to the script.

This means when you do this:
./daemon.php --string hello sweet world --url ww.google.nl


It will give you the following array values:
./daemon.php
--string
hello
sweet
world
--url
www.google.nl


This was not very convenient for me, because I wanted to pass a string that contains whitespaces to my daemon.

The following PHP function turns the above array into this:
string = 'hello sweet world'
url = 'www.google.nl'


<?php
function make_arguments_usable($argv) {
 
$i = 0;
$runmode_current = array();
 
foreach ($argv as $k=>$arg) {

if (substr($arg, 0, 2) == '--' && $i > 0) {

$runmode_current['name'] = substr($arg, 2, 16);
$runmode_current['i'] = $i;

if (isset($argv[$i+1])) {

if (substr($argv[$i+1], 0, 2) != '--') {

$store_runmode[substr($arg, 2)] = $argv[$i+1];
} else {

$store_runmode[substr($arg, 2)] = true;
}
} else {

$store_runmode[substr($arg, 2)] = true;
}
} else if (isset($runmode_current['i']) && $i != $runmode_current['i']+1 && $i > 0){

$store_runmode[$runmode_current['name']] .= ' '.$argv[$i];
}

$i++;
}
 
return $store_runmode;
}
?>


In this function, I purposefully do not use the first string that contains the scriptname.

If you want to set the runmode in your daemon, you can use this function like this:
$arguments = make_arguments_usable($argv); // $argv is reserved
 
foreach ($arguments as $k=>$v) {

$runmode[$k] = $v; // $runmode['some'] = 'thing cool';
}


I hope this can be useful for somebody.

#248. Evgeniy on 19 October 2011

Gravatar.com: EvgeniyThank you for the example. !
I have a problem with running the daemon.
I do so:

$ /usr/bin/php  -q /var/www/dt_parser.php
In the logs get:
[Oct 19 11:36:51] notice: Starting simple daemon, output in: '/var/log/simple.log'
[Oct 19 11:36:51] emerg: simple daemon is still running. Exiting [l:1262]
[Oct 19 11:36:51] info: Process was not daemonized yet, just halting current process


I close the terminal, and after re-connection can not detect the process.

I do not see the process in the list of server processes.
What am I doing wrong?
Im using Ubuntu
Thank you!

#247. Adam on 18 October 2011

Gravatar.com: AdamHi, I'm trying to implement a daemon process to replace an hourly cron job.

The issue I'm currently running into, is that even though I specify an integer value to System_Daemon::iterate, the process continues to run, and loop (incrementing the count variable each time).

$thisMinute   = intval(date('i'));
$napSeconds = intval( ( (60 - $thisMinute) * 60) + 60);

if ( $napSeconds > 0 ) {

//echo "napSeconds " . $napSeconds ." is an Integer greater than 0n";
System_Daemon::iterate($napSeconds);

} else {
//echo "napseconds value is less than 0, override the value to iterate to be 60 seconds. n";
System_Daemon::iterate(60);

}

$cnt++;


What's occurring is that even though there is a non-negative, greater than zero integer passed to System_Daemon::iterate, the process keeps going and going, incrementing the count of the variable $cnt and seemingly ignoring the iterate call.

Is there anything else I need to be aware of or perhaps a method in addition to iterate here -

again, my goal is to replace an hourly cron with a daemon process.

Thanks in advance,
Adam

#246. Peter on 14 October 2011

Gravatar.com: PeterThis is great!
I'm using it for a project at the moment.
But i wonder, does "sysMaxExecutionTime" actually do anything?
If i set it to 10 as test it doesn't kill the daemon after 10 seconds/minutes.

... [more] Which brings me to the next question, is there an option or command that allows me to kill the daemon if it runs too long? Let say after 10 minutes if it's still running : kill it.
I can do a date() with execution and compare, when it's higher and execute System_Daemon::stop() for example. But i just wondered if there's something better than that.

#245. Claudius Coenen on 06 October 2011

Gravatar.com: Claudius CoenenHi and thanks for the Daemon-Class!

I ran into a minor problem with stopping my daemon, and added System_Daemon::isRunning() to my while-loop.

I thought i mentioned it here, in case anyone else has the same problem. When i stopped my daemon with /etc/init.d/awesomedaemon stop, the log-messages switched from "daemon" to "non-daemon", but the service continued to run. Adding the check for "isRunning" solved that problem.
... [more]
Now it exits just fine!

#244. Adam on 29 August 2011

Gravatar.com: AdamThe script works great, apart from writing the initd. I get an error - unable to forge startup script for non-existing daemon_filepath. I am running on CentOS.

#243. Andrew on 26 August 2011

Gravatar.com: AndrewGreat stuff..
We use it for our daemon with CentOS. It never dies even for a minutes in months.
One thing that bugging me is memory usage for the daemon itself. I tested the daemon to run a simple task and it consume > 200MB. Have any idea about this?

Our daemon only process two lines:
... [more] while (!System_Daemon::isDying())
{
Proc_Close (Proc_Open ("/usr/bin/php /opt/web/anl/isat/engine/MTBillSendChildProc.php& > /dev/null", Array (), $fsx));

System_Daemon::iterate(2);
}

#242. JW on 12 August 2011

Gravatar.com: JWinteresting class you got. I'm running into a problem where I can't seem to get the init.d script to stop the daemon properly and I wind up having to kill -9 the process. Let me explain what I'm trying to do with your script.

I'm trying to build out a simplified rsyslog parser. I have a number of hosts on my network that write to my centralized syslog server. In addition to raw file logging, I have a named pipe that the syslog will output to as well. What I'm trying to accomplish is writing a script that will read the named pipe and check each line for predefined patterns for problems. If a line matches, it will log the problem line and notify somebody about the issue.

I'm trying to the script read in a configuration file/settings from either a flat file or mySQL DB table. These configurations will contain the REGEXP and notification settings, so they need to be updated on the fly and reread in if possible without having to fully restart the parsing script.

I'm in the initial stages of getting all this put together and here is some basic code that I put after "// Here comes your own actual code" in your example:

$queue = array();
$pipefile = '/var/spool/rsyslog/rsys_fifo';
$pipe = fopen($pipefile,'r+');
 
if(!$pipe) die('unable to open the named pipe');
stream_set_blocking($pipe,false);
while(1) {
while($input = trim(fgets($pipe))) {
stream_set_blocking($pipe,false);
$queue[] = $input;
}
$job = current($queue);
$jobkey = key($queue);
if($job) {
if(preg_match("/MATCHTHISLINE/i",$job)){
mail_alert($job); // test function
}
next($queue);
unset($job,$queue[$jobkey]);
} else {
stream_set_blocking($pipe,true);
}
}


I can start the daemon just fine using the init script, but I can't stop it. It just times out. Trying to do a kill -0 on the PID does not do anything and I have to do a kill -9 to stop it.

#241. Gene on 04 August 2011

Gravatar.com: GeneNevermind...got it...You need to put the path to PHP as the first line inside of your PHP file. so:
#!/usr/local/bin/php
<?php
....
?>

#240. Gene on 04 August 2011

Gravatar.com: GeneThis works great except for one simple problem. I cannot run my php by typing "./file.php"

I have to run it by typing "php ./file.php"

This wouldn't be a problem except for the startup script is trying to run it as "./file.php"
... [more]
Anyone have an idea how I can edit the command the startup script uses, or update my server to not need the "php" in front of the command? Thank you for your help!

#239. Andrew Blake on 01 August 2011

Gravatar.com: Andrew BlakeWould make a small donation if I could find a "Make Donation" button somewhere? Apologies, it is probably here somewhere, I will look again in the future when I get a chance.

Cheers
Andrew

#238. Andrew Blake on 01 August 2011

Gravatar.com: Andrew BlakeFantastic! Seems to be working perfectly. Will make small donation now - wish I could make it bigger - but not rich!

My linux Knowledge is very poor so will note the only minor thing I noticed here rather than trying to figure out how in PEAR. For some reason the kill command didn't work for me (though I never investigated why), and then once running trying to just run it again this time with the --write-initd argument wouldn't generate the init.d file. I had thought it might kill the daemon and restart. I just rebooted, and ran again with --write-inid and worked perfectly.

Thankyou

#237. Andrew Blake on 01 August 2011

Gravatar.com: Andrew BlakeHoping it works - looks good. Was googling for php daemon. Will be trying it today and will comment back. I have a hungry bit of code generating emails with swiftmail containing pdf attachment made by webkittoppdf. The emails queue in a table. Currently have been exec'ing background task to call my mail_queue.php but no matter what I try to ensure this is single instance I get race conditions problems that cause the odd delay or duplication. The answer is to turn it into a daemon.

Cheers for the post.

#236. yuki on 17 July 2011

Gravatar.com: yukiI want to ask about running php as a daemon to accept and inject file to port. I'm using postfix to build email server and i want to do some phrasing (to find url in incoming email) to incoming mail using php script. So the scenario is:

incoming mail-->postfix-->php phrasing-->postfix-->destination.

Postfix will receive incoming mail, then inject it to port, for example port 10033, then script php will receive and phrase it, after that, script php will inject it back to other port (e.g port 10034).
... [more]
So how do i configure php so the script will be able to receive then do phrasing and inject to port?

many thanks for your answer.

#235. Nemanja on 07 July 2011

Gravatar.com: NemanjaBrilliant, precise, informative, descriptive, accurate!

Thank you very much for this exquisite article!

#234. Jean on 06 July 2011

Gravatar.com: JeanHey Kevin, great work on the Deamon class.
From what I've learned during my time as Perl developer, you might want to consider closing STD* handles before forking though (e.g. fclose(STDIN)). That should prevent errors when echo is called within the daemonized part of the script and it helps realiably detaching from the console.

#233. Jocko on 28 June 2011

Gravatar.com: JockoI have managed to get this up and running on one of my servers, but I am struggling with the second. I get this response in the shell: sh: /export: not found
sh: /export: not found

What is the problem here?

#232. Pinoy on 08 June 2011

Gravatar.com: PinoyThis is exactly what I'm looking for. Thank you!

#231. astaza on 06 June 2011

Gravatar.com: astazawow it's what i looking for, but about echo,
you say echo will error if it's work in this mothed, but if it's run in cronjob will output errors?

thanks

#230. Ismail on 01 June 2011

Gravatar.com: IsmailThanks for such a nice article....

#229. James Gillmore on 30 May 2011

Gravatar.com: James Gillmore@kirill, i had the same issue and solved it by simply changing the name of the php file so it's name was less than 15 characters. note: .php is included in the character count.

#228. kirill on 18 May 2011

Gravatar.com: kirillRegarding the script in the "Complex Example" section - here you start the daemon with System_Daemon::start() before you process --write-initd parameter. As process changes its identity upon the start - this causes problem "Unable to create startup file". To overcome that you could either move write-initd part up in the code or call script with

--no-daemon --write-initd
params.
Also, at ubuntu I have problems stopping / restarting the daemon with the generated init.d script. I got error:
warning: this system is not able to track process names
longer than 15 characters, please use --exec instead of --name

But even if I replace --name with --exec in the control script - I get another error - daemon does not stop but rather changes its mode to 'non-daemon' and keeps running. In this case it outputs log records to stdout, but can not be stopped with CTRL+C 0_o

#227. Alex on 12 May 2011

Gravatar.com: AlexHello Kevin, thanx for your excellent library

I am facing a problem when writing to the init.d folder. I'm getting the following error:

[May 12 03:49:03]   notice: No data dir found in either:  or 
[May 12 03:49:03] warning: Unable to create startup file [l:1134]
[May 12 03:49:03] notice: unable to write init.d script


I have the next permissions:

-rwxrwxrwx 1 root     root      3501 2011-05-12 04:00 session_cleaner.php /* My executable php file */
drwxrwxrwx 3 root root 4096 2011-05-11 20:28 System /* your lib */
drwxrwxrwx 2 root root 4096 2011-05-09 22:47 init.d


And finally my php code (session_cleaner.php)
<?php
 
$runmode = array(
'no-daemon' => false,
'help' => false,
'write-initd' => false,
);
 
// Scan command line attributes for allowed arguments
foreach ($argv as $k=>$arg) {
if (substr($arg, 0, 2) == '--' && isset($runmode[substr($arg, 2)])) {
$runmode[substr($arg, 2)] = true;
}
}
 
// Help mode. Shows allowed argumentents and quit directly
if ($runmode['help'] == true) {
echo 'Usage: '.$argv[0].' [runmode]' . "n";
echo 'Available runmodes:' . "n";
foreach ($runmode as $runmod=>$val) {
echo ' --'.$runmod . "n";
}
die();
}
 
// Include Class
error_reporting(E_ALL);
require_once 'lib/System/Daemon.php';
 
// Setup
$options = array(
'appName' => 'session_cleaner',
'appDir' => dirname(__FILE__),
'appDescription' => 'Cleans up the /Indexing/storage/ directory from expired session files.',
'authorName' => 'Alexandros Biratsis',
'authorEmail' => 'abiratsis@gmail.com',
'sysMaxExecutionTime' => '0',
'sysMaxInputTime' => '0',
'sysMemoryLimit' => '1024M',
'appRunAsGID' => 1000,
'appRunAsUID' => 1000
);
 
System_Daemon::setOptions($options);
 
// This program can also be run in the forground with runmode --no-daemon
if (!$runmode['no-daemon']) {
// Spawn Daemon
System_Daemon::start();
}
 
// With the runmode --write-initd, this program can automatically write a
// system startup file called: 'init.d'
// This will make sure your daemon will be started on reboot
if (!$runmode['write-initd']) {
System_Daemon::info('not writing an init.d script this time');
} else {
if (($initd_location = System_Daemon::writeAutoRun()) === false) {
System_Daemon::notice('unable to write init.d script');
} else {
System_Daemon::info(
'sucessfully written startup script: %s',
$initd_location
);
}
}
 
// This variable gives your own code the ability to breakdown the daemon:
$runningOkay = true;
 
// While checks on 2 things in this case:
// - That the Daemon Class hasn't reported it's dying
// - That your own code has been running Okay
while (!System_Daemon::isDying() && $runningOkay) {
// What mode are we in?
$mode = '"'.(System_Daemon::isInBackground() ? '' : 'non-' ).'daemon" mode';
 
// Log something using the Daemon class's logging facility
// Depending on runmode it will either end up:
// - In the /var/log/logparser.log
// - On screen (in case we're not a daemon yet)
System_Daemon::info('{appName} running in %s %s/3',
$mode,
$cnt
);
 
$runningOkay = true;
try{

$handle = opendir('storage/');
if ($handle) {
 
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
System_Daemon::info($file.' found!');
}
}
closedir($handle);
 
}
else{
System_Daemon::err("Unable to open {$handle} directory!");
$runningOkay = false;
}
}
catch(Exception $e){
$runningOkay = false;
System_Daemon::err($e->getMessage());
}


if (!$runningOkay) {
System_Daemon::err('{appName} produced an error, so this will be my last run');
}
 
// Relax the system by sleeping for 10 sec
System_Daemon::iterate(10);
}
 
// Shut down the daemon nicely
// This is ignored if the class is actually running in the foreground
System_Daemon::stop();
?>


Do you have any idea why I can't write to init.d folder?

Thanx a lot
Alex

#226. fforex on 11 May 2011

Gravatar.com: fforexgreat article, i found this trying to make a cron job run at frequencies less than 1 minute(in seconds). as i can't found anything useful i was able to get into this article searching google. i installed the required stuff easy with my Slackware and tried the simple example with the infinite loop. works perfect for my needs, i really appreciate the article. thanks.

#225. Adam on 05 May 2011

Gravatar.com: AdamThanks man for both info & download

#224. Simon on 05 May 2011

Gravatar.com: SimonMany thanks for this. I'm only having one small issue: I'd like to have the init.d script report a FAIL if the daemon isn't started due to it being unable to connect to the database. However, System_Daemon::stop doesn't let you return an error, and just using an exit(1) leaves the pid file around and appears to be ignored by the init script, so it looks like the daemon started OK. Is there a way to do this?

#223. Ed on 02 May 2011

Gravatar.com: EdUseful, thanks for the work you've done on this project. In order to create the startup script, does the file need to be in /etc/init.d/ ?

My script is chmod a+x, owned and grouped to root, but it's still not writing. Here's /var/log

[May 02 16:15:30] notice: Starting acibind daemon, output in: '/var/log/acibind.log'
... [more] [May 02 16:15:30] info: Changed identify to '':''
[May 02 16:15:30] notice: No data dir found in either: or
[May 02 16:15:30] warning: Unable to create startup file [l:1134]
[May 02 16:15:30] notice: unable to write init.d script
[May 02 16:15:30] err: Not receing data from ZM. [l:183]

Any help is much appreciated!

Thanks,
Ed

#222. Jason on 20 April 2011

Gravatar.com: Jason@Kevin: Thanks, I have found out how to send out custom signals. Looking through the list of signals SIGUSR1 and SIGUSR2 are good to use, however we would probably need more than 2 different signals to differentiate between queries to run.

Could we technically send any signal as long as we set it using setSigHandler? Or would certain signals have an effect on the daemon (like SIGKILL)?

#221. Kevin on 19 April 2011

Twitter.com: kvz@ Jason: As the article explains, never use stdin/out/err as it will crash your daemon the moment it wants to use it & your terminal session is gone.

You can open a tcp port, or for very rudimentary communication, can use custom POSIX signals. Or work with a jobs table or filebased queue, etc.

#220. Kevin on 19 April 2011

Twitter.com: kvz@ Jason: As the article explains, never use stdin/out/err as it will crash your daemon the moment it wants to use it & your terminal session is gone.

You can open a tcp port, or for very rudimentary communication, can use custom POSIX signals. Or work with a jobs table or filebased queue, etc.

#219. Jason on 19 April 2011

Gravatar.com: Jason@Kevin: What I mean is there a way to communicate with the daemon i.e. send it a command whilst it's running which it can detect and perform some specific code if present?

We want the daemon to run a mysql query but only when we tell it to, we don't want the daemon doing anything else the rest of the time (but obviously still keep running in the background).

So the daemon can't check to do anything, it can only take in input.
... [more]
I know it can read in arguments through $argv but this would only work initially when you start up the daemon. It has to somehow dynamically retrieve this. Maybe using php://stdin or something but I don't know the best way.

Any help would be appreciated on this!

#218. Kevin on 19 April 2011

Twitter.com: kvz@ Jason: arguments are handled by the wrapper script, not by the daemon class itself. So that's something you code yourself or take from the examples

#217. Jason on 19 April 2011

Gravatar.com: JasonGreat script!

How can you detect if an argument has been passed to the daemon whilst it is running?

start dameon...
./daemon.php

then a command is executed on the server...
./daemon.php --blah

while (!System_Daemon::isDying()) {
 
// detect if blah has been called
}

#216. Kevin on 17 April 2011

Twitter.com: kvz@ Adolphe: Your problem is already covered in the trouble shooting section.

#215. Kevin on 17 April 2011

Twitter.com: kvz@ Andy: you can also use isInBackground() for that.

@ Robert: Nope, pretty busy as it is, thanks : )

@ Tom Dexter: Thanks for chiming in.
... [more]
@ Jim McNeely: Maybe you can try installing pear with homebrew on OSX

#214. Tom on 16 April 2011

Gravatar.com: TomOoops! Just did: yum install php-process.

That enables the posix functions apparently.

Thanks anyway!

#213. Jim McNeely on 16 April 2011

Gravatar.com: Jim McNeelyI'm having a lot of trouble making this work with PEAR. "which pear' returned nothing until I figured out it no longer comes with Mac OS X 10.6. I finally figured this out, I think, and it returns this:

err: [PHP User Error] PEAR_Exception not found?! [l:519]

Which upon examination shows it is looking for some PEAR exception classes; I see these buried in the PEAR sub file Exception.php, but it still isn't working. I would really love to use this, any help would be hugely appreciated.

#212. Tom on 16 April 2011

Gravatar.com: TomHi Kevin, (or anyone for that matter!)

Still using and loving your pear package!

Trying to use it on Fedora 14 at the moment, after playing with it on Ubuntu.
... [more]
When I go to run the daemon I get the following error:

PHP Fatal error: Uncaught System_Daemon_Exception: PHP is compiled without --enable-posix directive in /var/www/testproject/system/system.php on line 85
#0 /var/www/testproject/system/system.php(85): System_Daemon::start()
#1 {main}
thrown in /usr/share/pear/System/Daemon.php on line 552
<font color=#ff0000>
Fatal error: Uncaught System_Daemon_Exception: PHP is compiled without --enable-posix directive in /var/www/testproject/system/system.php on line 85
#0 /var/www/testproject/system/system.php(85): System_Daemon::start()
#1 {main}
thrown in /usr/share/pear/System/Daemon.php on line 552
</font>

Will I just have to re-compile php without the -enable-posix argument?

Thanks in advance for your help!!

Tom

#211. Adolphe on 15 April 2011

Gravatar.com: AdolpheHi Everyone,
i use systemdaemon to create a server that listens for incoming connections and hit a function to query a MS SQL database.
When not running in background, mssql_connect works perfectly, everything seems good. However in background mode mssql does not work.

How can you help me on this ?

#210. Tom Dexter on 26 March 2011

Gravatar.com: Tom DexterJust a word of caution to others writing daemons: Many of you may have discovered, as I did, that in order for your daemon to background properly (especially when being started from other processes like gui service managers) you need to close STDOUT and STDERR with for example fclose(STDOUT), otherwise programs attempting to start your service can hang.

I found out the hard way that this can have the nasty side affect of having some other unwanted resource becoming the default file descriptor for STDOUT (2) or STDERR (3). In my case STDOUT became the file handle for my MySQL unix socket! As soon as I accidentally left a print statement in my script it started mysteriously closed the connection causing "MySQL has gone away" errors!

To prevent this, early in your script before opening any logs or database connections, close ALL three of STDIN, STDOUT, and STDERR and open global file handles to three things to take their place, in order (using a dummy for STDIN, and some log file for the others) such as:
... [more]
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
$GLOBALS['STDIN'] = fopen('/dev/null', 'r');
$GLOBALS['STDOUT'] = fopen('/var/log/default.log', 'a+b');
$GLOBALS['STDERR'] = fopen('/var/log/default.log', 'a+b');

That will cause any erroneous output to write harmlessly to those logs. Note that the names of those globals are irrelevant, the important thing is the ORDER they're in, which causes them to get the file descriptors 1, 2, and 3 respectively.

Be glad you didn't have to figure this out :D

Tom

#209. Tom Dexter on 26 March 2011

Gravatar.com: Tom Dexter@Dan: To perform an update of some sort on shutdown just override the default signal handler such as:

System_Daemon::setSigHandler(SIGTERM, 'your_function');

In that function (which gets passed the signal number like any signal handler) perform your update and then call System_Daemon::stop();

#208. Dan on 24 March 2011

Gravatar.com: DanI have set up the init.d script and it is working great, when I use "service app_name stop" to stop the daemon, how can I use System_Daemon::isDying() to trigger an action? I want to write to the database one last time before it shuts down. I have an if statement in the while loop but it is not firing when I shut it down.

btw - this is an awesome class

Thanks
... [more]
Dan

#207. Robert on 21 March 2011

Gravatar.com: Robertsounds very interesting, wish I was a php programmer. Any interest in contract work?

#206. Andy on 21 March 2011

Gravatar.com: AndyHey Kevin, thanks for your great work on this!

It would be nice if System_Daemon::start() would return a success flag, so that one could continue/abort based upon whether or not the daemon actually started.

#205. Kevin on 10 March 2011

Twitter.com: kvz@ Andy: System_Daemon now reports when you try setting long appnames: https://github.com/kvz/system_daemon/commit/93ed645b9fa855f4c02d0f6a65e776d312df88eb

@ Andre Agassi: If your code has an existing __autoload function then this function must be explicitly registered on the __autoload stack. This is because spl_autoload_register() will effectively replace the engine cache for the __autoload function by either spl_autoload() or spl_autoload_call().
From: http://www.php.net/manual/en/function.spl-autoload-register.php

#204. Andre Agassi on 06 March 2011

Gravatar.com: Andre Agassi__autoload isn't called in daemon code. Please provide reason why not

#203. Andy on 04 March 2011

Gravatar.com: AndyOne observation I've made: The file that is invoked by init.d must be less than 16 characters total, including file extension.

If the file is not less than 16 characters, the daemon will not stop. When you issue a restart command, a new, simultaneous process will be spun up.

Doesn't work: mydaemonfile.php
... [more] Works: mydaemonfil.php

Cheers,
Andy

#202. Kevin on 04 March 2011

Twitter.com: kvz@ Stefan: I don't support Gentoo, but if you want you can write a Gentoo file and contribute it?

#201. Kevin on 04 March 2011

Twitter.com: kvz@ Tom: You should change:

'appRunAsGID' => $gid,
'appRunAsUID' => $uid,

#200. Kevin on 04 March 2011

Twitter.com: kvz@ Morten: Please make sure you're running the latest version (1.0) and don't use caps in your daemon names.

#199. Shane Harter on 09 February 2011

Gravatar.com: Shane HarterI recently open-sourced a Daemon platform I wrote that we've used for a long time in Production.

https://github.com/shaneharter/PHP-Daemon

I'm posting this because the commenter before me was talking about switching a Cron to a daemon. My library is similar to yours in many ways but a feature this has that readers here might find useful is a built-in timer. Suppose you wanted to run some code every second. Or maybe 5 times a second.
... [more]
Also, I built a pretty nifty auto-restart feature to side-step the (very correct) memory issues you wrote about.

Shane

#198. Anish Sharma on 09 February 2011

Gravatar.com: Anish SharmaVery good information on CRON vs. Daemons. Will try it for sure!

#197. Kumar Chetan Sharma on 09 February 2011

Gravatar.com: Kumar Chetan Sharmanow is the time to convert all cron jobs to daemons, thanks :-)

#196. Wilson on 13 January 2011

Gravatar.com: WilsonOh this is exactly what I need because I am thinking of adding a module in the admin section of my site which will automate the adding of entries to the database on a daily basis pulled from a pre-entered pool of data. I can accomplish the same thing with Cron but I hate having too much external dependencies since I always aim when coding to have my code easily portable from one server to another without too much re-configuring.

#195. Stefan on 10 January 2011

Gravatar.com: StefanHey there, absolute great class you built here!!

I have one slight problem:
OS = gentoo

... [more] when i call System_Daemon::writeAutoRun() i get an error:
No autoRunTemplatePath found
when i add this variable to Linux.php in OS-folder i get:
No autoRunTemplateReplace found
when i add this variable to Linux.php i get:
notice: No PROPERTIES found in autoRun template

i'm stuck here, please help me out
thanks in advance!!

#194. Morten on 03 January 2011

Gravatar.com: MortenThank you very much for a great class. :-)

We're running a daemon with it and using monit to make sure it's always running.

Part of the function is calling an external service - but since this has some downtime during the night, we have a cronjob killing the daemon at that time and then monit makes sure it gets started again. This seems to work just fine.
... [more]
But - now and then we've experienced that more than one thread of our daemon is runing!

How can this be? How can we prevent it from happening?

Thanks for any help.

Kind regards and a happy new year to all.

#193. Joerg on 06 December 2010

Gravatar.com: JoergHi,
first of all: This class is awesome. Thanks a lot!

But now my question, which is not 100% related to your code:
I try to create a php-Daemon, which parses an logfile and saves each line to a database-table.
... [more] The logfile is actively written to and also will be rotated every night.
Do you got such a environment build up successfully with php and System_Daemon? I searched several days in the internet, but the only thing I found was a CPAN-module for perl called File::Tail, which does exactly what I need but in the wrong language. All php-code I found just implemented something like "return the last x lines of messages in a logfile" or weren't aware of logrotate :-(

Thanks in advance

#192. Kyle on 03 December 2010

Gravatar.com: KyleI found when running the /etc/init.d/$file stop, that my command was not really being stopped.

To fix this I had to shorten the name of my appName

'appName' => 'jque1',
... [more] from
'appName' => 'jobqueue_processor1',

and then this worked. It seems that /proc/$ids/status truncates thus causing start-stop-daemon to fail to shutdown as the --name does not match

#191. Tom on 02 December 2010

Gravatar.com: Tom@Brian

Many thanks for the reply!

I was under the impression that the UID and GID of 1000 was for the root user, my mistake!
... [more]
Anyway, my passwd file says that root is 0:0 but after entering these into the daemon option I get the following errors:

[Dec 02 20:45:59] err: Unable to change group of file '/var/run/daemon' to 0 [l:1425]
[Dec 02 20:45:59] crit: Unable to change identity [l:1281]
[Dec 02 20:45:59] emerg: Cannot continue after this [l:1283]

Am I overlooking something else now?

Thanks for your patience!

Tom

#190. Brian on 02 December 2010

Gravatar.com: Brian@Tom

You probably have these two options set.

"appRunAsUID"=>array(
... [more] "type"=>"number/0-65000",
"default"=>0,
"punch"=>"The user id under which to run the process",
"example"=>"1000",
"detail"=>"Defaults to root which is insecure!",
"required"=>true),

"appRunAsGID"=>array(
"type"=>"number/0-65000",
"default"=>0,
"punch"=>"The group id under which to run the process",
"example"=>"1000",
"detail"=>"Defaults to root which is insecure!",
"required"=>true),

Look in your /etc/passwd file and compare the uid and gid for root

#189. Tom on 29 November 2010

Gravatar.com: TomKevin,

Once again thanks for the awesome work. Just having some troubles getting the daemon to run as root. I am running a clean ubuntu install, with your example daemon above. I have chmod'd the file as you say above, but everytime I run it it says changing identity to tom:tom. I have tried chown'ing the file too, not sure if that would help the situation?

Thanks.

#188. Tom Dexter on 12 November 2010

Gravatar.com: Tom DexterRegarding my last post: I'm trying to understand the rational behind the requirement that the pid file be in a directory unique to the appName. In my case I have one master script that I use for two different monitor services based on a name passed to it. My pid files and log files (via Pear Log) are in fact specific to the proper monitor based on that name it receives, but they are using the same appName with both pid files under that directory. I can easily change it to make the appName and the subdirectory unique, but I'm not understanding how/if my current setup could cause any conflict.

#187. Tom Dexter on 12 November 2010

Gravatar.com: Tom DexterHi Kevin. I've been having an occasional occurrence in my daemon that I can't figure out. I occasionally get the "Process was not daemonized yet, just halting current process" when stopping the service when it absolutely was daemonized. I've traced it to the isRunning function failing the file_exists check on the pid file, but the pid file certainly should be there at that point. I'm running this under CentOS (I HATE their init scripts by the way), and am stopping the daemon with their killproc -p <pidfile> syntax. I've verified that the init script would not try to delete the pid file until after the daemon has stopped. Any ideas what might cause that?

#186. Kevin on 09 November 2010

Twitter.com: kvz@ KevBurnsJr: Wow, I mention there's no memory leaks, 15 minutes later someone reports a memory leak : )
But I fixed it as well:
http://pear.php.net/bugs/bug.php?id=18031
So be sure to upgrade when I push the new release (or get it from github if you can't wait)

#185. Kevin on 08 November 2010

Twitter.com: kvz@ Tom: Like I mentioned in the comments before, I've found an unmaintained PEAR package: Fork. Maybe that can do what you want. I didn't have plans to make this a system_daemon feature as I've always felt that it should be a simple and basic building block.

@ KevBurnsJr: I'm using it in production yes, other folks told me they have as well. However there seem to be quite some edge cases in which a deamon stops working (use echo 1 time, have a dependency that tracks some kind of log/history in an array, thus eventually becoming too large for memory). Because there are plenty other examples and it's hard to cover all of them at first try, you should use monit to restart your daemon & notify you whenever that happens.
There are currently no known bugs that will cause it in PHP or System_Daemon itself, but anything put in your execution loop can pretty easily kill your daemon.

#184. KevBurnsJr on 06 November 2010

Gravatar.com: KevBurnsJrGreat article. I found this post after stumbling across a PHP port of Resque (a Redis-based queue implementation originally written in Ruby) that lets you run queue workers as PHP daemons. I'd always thought it was possible, but never thought that anyone would be crazy enough to try it.

Have you ever actually deployed a PHP daemon as part of a production system?

Do you know anyone who has?

#183. Tom on 06 November 2010

Gravatar.com: TomKevin,

Thanks for the awesome tutorial, just what I need!

I am looking to create a daemon in php which will handle commands send to it. However when it is sent a command, i would like it to spawn a kind of child daemon to process that command, otherwise the main daemon would be bogged down doing one command and not be able to handle subsequent commands. Is this possible with this package?
... [more]
How would I go about doing it?!

Thanks again.

#182. Kevin on 31 October 2010

Twitter.com: kvz@ robert: Need a little more details to be of any help.

#181. robert on 28 October 2010

Gravatar.com: robertHi.

many thanks for your great work.

Unfortunately I have an issue regarding using of the init.d
... [more]
This code appears in the console if i try to use the written init.d file

Unable to start /var/daemon/bookingd_test/scriptd.php: Exec format error (Exec format error)

Do I miss something important??


System: Debian lenny
br
robert

#180. Kevin on 11 October 2010

Twitter.com: kvz@ gazbond: Haven't tested it on OSX. But I'll soon get an iMac so I can see if I can make it work. In the mean time you could verify if you have the pcntl extensions in your PHP?

@ Alessandro Desantis: Use ob_start() or maybe even use classkit to overrule echo (dirty)

@ frank: System_Daemon init.d files have protection against this. Should not be possible if you use them
... [more]
@ Thom: Thanks :)

@ Greg J: Wow. Thanks for reporting the fix!

#179. Greg J on 07 October 2010

Gravatar.com: Greg JIm back. I have resolved the problem mentioned in my previous post from 3rd October (see post below) so I thought it might be useful to record what causes this issue and how to fix it.

for the record, the file runs fine with the following command

php myfile.php
... [more]
its only when I attempt to run it as an executable with the following command that I get the problem

./myfile.php

gives me this error

Extension '/var/www/hb_daemon.php' not present.

THE PROBLEM
The problem is that the script I had originated from a windows environment. I thought by deleting a line then recreating it would remove the characters at the end that was causing the problem but the end line characters appear to be built into the file somehow. I have been using gedit in ubuntu 10.04 (lucid) to edit in linux. I tried several other editors but couldnt seem to shake the problem. there seems to be a mysterious ^M at the end of every line. this appeared when I tried using vi but was invisible in all other editors.

THE FIX
you need to run dos2unix over the file.

this program was not installed in my distro so I ran the following command to install it.

sudo apt-get install tofrodos

after that, it still didnt run, said file not found, which is apparently due to a bug so the workaround is to run the following commands from the /usr/bin directory

sudo ln -s fromdos dos2unix
sudo ln -s todos unix2dos

once that was done, I simply ran

dos2unix myfile.php

once done i can run a executable php file from the command line by typing

./myfile.php

happy days!

good luck

Greg J

#178. Greg J on 03 October 2010

Gravatar.com: Greg Jhey, this is great stuff and very quick and easy to implement, however, I cannot seem to get past the following error when I make the daemon an executable and try to start with /etc/init.d/hb_daemon start. the error I get is:

Extension '/var/www/hb_daemon.php' not present.

Forum posts I have found say that php cannot be found in the path however I can confirm this.
... [more] php indeed resides in /usr/bin and that path is specified in the init.d file that is created from the $path = System_Daemon::writeAutoRun(); command.

The daemon starts fine when I use the command php hb_daemon.php from the folder where the daemon is located. I found the earlier post from december and tried all the things you suggested but the problem remains.

What happens if you try
php ./daemon.php?
- it runs as expected

If it works, you need to chmod u+x daemon.php
- did this

and maybe put /usr/bin/php in your /etc/shells
- did this

and maybe put #!/usr/bin/php -q in the head of your script.
- already there

The script is simple, it just counts to 5 at 1 second intervals then the daemon stops.

I am running the apt-get installation of php on ubuntu 10.04. PHP 5.3.2-1ubuntu4.5 with Suhosin-Patch (cli) (built: Sep 17 2010 13:41:55)

Any help would be appreciated

Thanks in advance

Greg J

#177. Thom on 01 October 2010

Gravatar.com: ThomThanks for putting this together. I had my first daemon up and running in an hour.

Great work!

#176. frank on 19 September 2010

Gravatar.com: frankist there anway to prevent multiple instances on running?im on an debian etch and for some reasons i had two instances running which messed up everthing!

help appreciated

fra*

#175. gazbond on 17 September 2010

Gravatar.com: gazbondSystem_Daemon does not work on OSX! Anyone confirm this?

#174. Alessandro Desantis on 10 September 2010

Gravatar.com: Alessandro DesantisDo you know if it is possible to disable echoing with this class?

#173. Kevin on 12 August 2010

Twitter.com: kvz@ chris & Utahcon: Found your problem. You are not supposed to use caps in unix daemon names.
I want to build protection against this but I'm gonna need some code samples cause by the looks of it, Options.php already has it:

protected function strIsUnix( $str )
{
return preg_match('/^[a-z0-9_]+$/', $str);
}


So I'm wondering how exactly you got passed that..

@ Tom Dexter: I'm having a hard time trying to grasp your problem without being able to look at & play with code. Have any?
You could also fork http://github.com/kvz/system_daemon, make the required changes, and send me a pull request.
That would work very well, actually.

#172. utahcon on 30 July 2010

Gravatar.com: utahcon@chris @kevin

I am sorry I didn't come back to report but I found the same thing as @chris. The init.d script that was written on Ubuntu was bad as it called the wrong name, or something (I don't recall now).

I had to puttz with the init.d to make it work properly.

#171. .: Pampa :. on 26 July 2010

Gravatar.com: .: Pampa :.Nice tut Kev!

I came here looking for PHP daemons (actually written in pure PHP code) and found a really easy to understand tut!

Hardly I've learned your troubleshoot tips, but good to let the newbies know.
... [more]
Congrats :)

#170. chris on 12 July 2010

Gravatar.com: chrisi'm curious... looks like i just figured out what might cause my problems.. i've had called my Skript "messageQueueBroker.php", when i tried your example again i named it "logparser.php" and all works fine..

are there any known problems with filelength? The appName in both cases was "logparser", just the filename/length differs..

#169. chris on 12 July 2010

Gravatar.com: chris@Kevin

First many kudos to your work, we've been playing around with some hand-written process controll mechanism here..

i'm experiencing the same behaviour as @Utahcon.. i'm using Ubuntu 8.04 and latest Version of System_Daemon from pear (0.10.3)

When i call

/etc/init.d/myscript restart


a 2nd instance is created, and so on.. the script also switches from background mode into non-background, according to the logfile..

i can reproduce this behaviour with your example snipped above, just removed the 3-run-limitation.


the script runs with user/group "0/0", got +x for execution.. and is started with root privileges..

hope this gives you an idea how to track this down.. :)

#168. Tom Dexter on 04 July 2010

Gravatar.com: Tom DexterOne question: I see that SIGCHLD is one of the signals you've implemented as a string. Are there php platforms that don't support that?

By the way...I tried implementing an option to override that restart_syscalls parameter of pcntl_signal in System_Daemon as I discussed previously. The change wasn't difficult, but for reasons I can't figure out, it doesn't behave as it does in scripts not using System_Daemon (even scripts forked as children of a daemon). Here's the behavior I wanted:

If my daemon gets a TERM signal while it's waiting for a child process with pcntl_wait or pcntl_waitpid, I want to immediately cancel the wait call and jump to my TERM signal handler which can kill the child process. This is exactly how it works in other scripts (again, even is child scripts spawned from a script running System_Daemon).
... [more]
For some reason however in the script using System_Daemon, when the wait call is interrupted by the receipt of the TERM signal, the script continues past the pcntl_wait call through the current iteration loop. Worse yet, in the code past that wait call, calls to pcntl_wifexited() and pcntl_wexitstatus() using the status from the wait all act as though the child ended normally when it actually hasn't exited at all!...totally perplexing.

I finally gave up...that one has me totally stumped.

#167. ppafford on 30 June 2010

Gravatar.com: ppaffordGetting this error: --enable-pcntl
Running on CentOS 5, how do I fix this?

I have the script (No running as daemon) and is triggered by incoming SOAP request which I want to kick off the daemon to process this.

#166. Tom Dexter on 30 June 2010

Gravatar.com: Tom DexterThanks for the filegroup() fix! I have a suggestion (one I'd even help with if you want to email me). I'm not sure if it would cause problems or not. The pcntl_signal php function has a third parameter (restart_syscalls) which defaults to true. If you want to be able to call pcntl_wait or pcntl_waitpid to wait for a spawned child and still be able to catch a signal for which you've assigned a function (that is, interrupting the pcntl_wait), that third parameter needs to be set to false or the pcntl_wait immediately resumes when the signal is received and won't call the handler function until the child exits (if in fact it ever does).

System_Daemon::setSigHandler currently has no way to use that option. In the project I'm working on I was able to work around that by not using pcntl_wait, but rather relying on a SIGCHLD handler and a loop. It'd be a nice feature to allow for that. Again, I'd be willing to help with that if you want to email me. Thanks!

#165. Kevin on 29 June 2010

Twitter.com: kvz@ Utahcon: Doesn't ring any bells. What version was this?

#164. Utahcon on 24 June 2010

Gravatar.com: UtahconI have setup a daemon using your PEAR class, and I have to say that was mighty handy.

I did a --write-initd and all went well.

start works just fine

but when I try to stop the script with

sudo /etc/init.d/myDaemon stop


it seems to change reporting from the log to STDOUT and my Daemon keeps running.

Ideas?

#163. Kevin on 10 June 2010

Twitter.com: kvz@ Daniele Palumbo: Deamons should run at all times using init.d/upstart scripts.

@ Mike: pcntl extensions are essential for the forking to work. You need PHP to support that.

@ Tom Dexter: Good catch, awesome! Fixed it here: http://github.com/kvz/system_daemon/commit/d9c1ef4cbdee037d250ec614c6f56e25f77d6524 and will be part of next release cycle.

#162. Tom Dexter on 28 May 2010

Gravatar.com: Tom DexterThanks for an awesome class! It'll be a life saver for me. In testing today I noticed that this line in Daemon.php is doing a fileowner() function call that should be a filegroup() call:

// Change File GID
$doGid = (fileowner($filePath) != $gid ? $gid : false);


Thanks again!

#161. Mike on 26 May 2010

Gravatar.com: MikeI get the following error when trying to start my daemon:

<CODE="text">PHP Warning: PHP Startup: Unable to load dynamic library 'usr/lib/php5/20060613/pcntl.so' - /usr/lib/php5/20060613/pcntl.so: cannot open shared object file: No such file or directory in Unknown on line 0</CODE>

The pcntl.so file does not appear to exist in that directory. Any idea why it is trying to call this file? And, why it doesn't exist there?

#160. ilovebonnie.net on 24 May 2010

Gravatar.com: ilovebonnie.netHello!

Thanks much for the great PEAR class. I found this to be incredibly useful and well-written. Unfortunately, I had a hard time figuring out what options I needed to set in order to get permissions issues dealt with. Particularly, I found it hard to find information about how to set the location of the log file or the pid file that you wanted the daemon to use.

I wanted to come here to let you know I wrote a little blog post about how users can set those options in case they are having similar problems due to permissions:
... [more] http://www.ilovebonnie.net/2010/05/23/log-file-location-and-pid-file-location-settings-for-the-php-system_daemon-pear-class/

Thanks again!

-ilovebonnie.net

#159. steve on 23 May 2010

Gravatar.com: steve@Kevin. Thanks for the info, I also had the permission issue with Fedora.

I modified the script to with the following:

$gid = 1000;
$uid = 1000;
 
if ($runmode['write-initd']) {
$gid = 0;
$uid = 0;
}
 
$options = array(
'appName' => 'tgsendmail',
'appDir' => dirname(__FILE__),
'appDescription' => 'Parses vsftpd logfiles and stores them in MySQL',
'authorName' => 'Steve',
'authorEmail' => '',
'sysMaxExecutionTime' => '0',
'sysMaxInputTime' => '0',
'sysMemoryLimit' => '1024M',
'appRunAsGID' => $gid,
'appRunAsUID' => $uid,
);
...
...
while (!System_Daemon::isDying() && $runningOkay && !$runmode['write-initd']) {
$runningOkay = true;
...
...

#158. Student Brands on 22 May 2010

Gravatar.com: Student BrandsThanks for the great information. I hope to be back soon. I have book marked it keep posting. Thanks again.

#157. Daniele Palumbo on 20 May 2010

Gravatar.com: Daniele PalumboHi,

i wish to know the best way to execute System_Daemon from web (exec? directly via browser?).

with system() seems not to fork, going into timeout after a while (php timeout).
... [more]
Also, i HAVE to set "runAppAsGID" and "...UID", but i am starting it from web...

thanks,
s.

#156. Kevin on 15 May 2010

Twitter.com: kvz@ Petri: System_Daemon defaults to root. You must have been using code that explicitly defines

array(
'appRunAsGID' => 1000,
'appRunAsUID' => 1000,
);


removing that should make them 0 as well.

#155. Petri on 09 May 2010

Gravatar.com: PetriI was having problems with writing the /etc/init.d/ startup file untill I realized the UserId and UserGroup this daemon wants to run. File permissions were fine to beginwith. CentoOS just does not have user Id nor group values 1000 by default.

By default:
'appRunAsGID' => 1000,
'appRunAsUID' => 1000,
... [more]
In CentOS, I had to change these to:
'appRunAsGID' => 0,
'appRunAsUID' => 0,

root has id and group = 0.

Now, this could potentially be a security risk if the daemon runs as root, therefore I suggest using the 0 values only when creating the startup script, and then use some other user values in actual run.

#154. Brian René Jensen on 02 May 2010

Gravatar.com: Brian René JensenHi Kevin.

I just wanted to thank you.

Great post - Very useful to me.
... [more]
I'm great at PHP, but bash doesn't really apeal to me. This way, I can write a ton of code to monitor my Ubuntu server with email statistics.

Thanks allot.
Bwyan

#153. Kevin on 29 April 2010

Twitter.com: kvz@ Manuel de Ruiter: Good!

#152. Manuel de Ruiter on 24 April 2010

Gravatar.com: Manuel de RuiterThank you Kevin for your reply on this problem. I've just did some checks with the iterate function and it makes a huge difference.

Without: 99.9% CPU is in use and with 0.0% CPU is in use. Also did some checks with sleep and usleep and now it works like a charm. Thank you Kevin!

#151. Kevin on 24 April 2010

Twitter.com: kvz@ haguey: Thanks for sharing

@ Rsk: And this does not happen when you run the init.d file it from the console?

@ Manuel de Ruiter: I don't see a sleep, let a alone a System_Daemon::iterate in your while loop. That will definitely exhaust your system's resources

#150. Manuel de Ruiter on 21 April 2010

Gravatar.com: Manuel de RuiterSorry for the double-post but I forget to add the $i++ add the bottom of the pastebin url. For the 'full' example please check: http://pastebin.com/hDA4udCA

#149. Manuel de Ruiter on 20 April 2010

Gravatar.com: Manuel de RuiterHello Kevin,

It's been a while since I visited you're tech-blog, but I'm facing the problem that the 'daemon' that I create consumes to much CPU.

I've got a VPS with Debian Lenny installed and default the load of that machine is ~0.15 (5 minutes). But when I activate the daemon the load of the machine goes up to 100% CPU usage. (Got one VCPU clocked at 1.8Ghz and have 2048MB RAM). The weird part is that it doesn't consume that much RAM (0.1% to 0.2%).

Here a little example of the output:

lighttpd  5781 48.1  0.2  51676  5696 pts/1    R    19:45  12:09 php -q /var/www/path/to/location/daemon.inc.php


I'm running the daemon under the lighttpd user cause that area is chrooted. Let me describe what I've done so far.

- Used the iterate and raised it up to 60s
- Checked my codes for leaks
- Modified the daemon code to minimum
- Made a blank daemon (only with the while)
- Set options manually
- Changed System_Daemon version

Example: http://pastebin.com/3HytDKpp

Let me know!

#148. Rsk on 20 April 2010

Gravatar.com: RskFor long days i was dependent on Cron for the daemon tasks. Now this system daemon looks really great. I have one issue when trying out.
I used the example script and added the php code as mentioned. And made it as a daemon and restarted the machine. On booting time the system waits for this process to execute , it keeps waiting over there until i remove it from the init.d.
Am i doing it right ?

#147. haguey on 06 April 2010

Gravatar.com: haguey@Kevin,

Thanks for you reply, it turns out the problem is that procfs on debian stores truncated process names...

so that if the daemon process name goes over 16 characters, start-stop-daemon will not find it using the -name option...
... [more]
check /proc/<pid>/stat to see if the processname is truncated. I guess other people unable to stop their daemon might have this problem.

#146. Kevin on 04 April 2010

Twitter.com: kvz@ Haguey: Is it possible you appended the 'd' to hagueyd later on? So after you wrote the init.d files?

@ Adi: Too bad.. If you share code we might be able to actually establish what's going wrong and maybe fix bugs whether on your or my part.

#145. Adi on 01 April 2010

Gravatar.com: AdiI just cldnt get it to work...when i tr ps -e or ps iaux..i dotn see the process der...i cant even get the init script up..im running the latest version..and after trying for 23 hours..i thot ill throw in the towel publicly here..:(

#144. Haguey on 29 March 2010

Gravatar.com: HagueyI'm having a bit of trouble starting and stopping my daemons.

when I issue ps ax I see my daemon running as:

/usr/bin/php -q /home/haguey/hagueyd.php
... [more]
The problem is that when I try to use /etc/init.d/haguey to start and stop the damon it never gets the correct process name.

it's trying to do TERM hagueyd and not TERM /usr/bin/php -q /home/haguey/hagueyd.php

Any ideas what I could be doing wrong?

thanks in advance!!

#143. Kevin on 24 March 2010

Twitter.com: kvz@ dave: On ubuntu there's a standard logrotate facility as - I'm sure - there is on other systems. You can just configure that system to keep system_daemon's log rotated as well.

@ Jocko: While I cannot reproduce this, this has been reported as a bug:
http://pear.php.net/bugs/bug.php?id=17254

... [more] And this is my proposed fix:
http://github.com/kvz/system_daemon/commit/11abe6dfb10888c82087c89554bf4db169a23cc7

#142. dave on 24 March 2010

Gravatar.com: daveIs there an example of setting up logging with log rotation? The default facility appears to have the logs growing without end...

#141. Jock0 on 23 March 2010

Gravatar.com: Jock0Hi Kevin,
Thank you for this helpful guide. I am trying to run a socket listener as a daemon, but get the following lines in the log file:
[Mar 23 16:30:00] notice: Starting socketdaemon daemon, output in: '/var/log/socketdaemon.log'
[Mar 23 16:30:00] info: Changed identify to 'root':'root'
[Mar 23 16:30:00] warning: [PHP Error] pcntl_signal(): Error assigning signal [l:1304]
... [more] [Mar 23 16:30:00] emerg: Unable to reroute signal handler: 0 [l:1308]
[Mar 23 16:30:03] notice: Starting socketdaemon daemon, output in: '/var/log/socketdaemon.log'
[Mar 23 16:30:03] info: Changed identify to 'root':'root'
[Mar 23 16:30:03] warning: [PHP Error] pcntl_signal(): Error assigning signal [l:1304]
[Mar 23 16:30:03] emerg: Unable to reroute signal handler: 0 [l:1308]

What is the problem, and how could it be fixed?

#140. Kevin on 18 March 2010

Twitter.com: kvz@ Menderezz: Hey. Thanks : ) That is actually true for all PEAR packages that haven't reached stable yet.
To circumvent you can either use the force argument -f, or append the state like: System_Daemon-beta so the installer knows that you know what you are doing : )

#139. Menderezz on 18 March 2010

Gravatar.com: MenderezzThanks Kevin, your example config was very helpfull, I just want to notify that upgrading System_Daemon on RHEL 5 is not possible, it gives some error, saying that it's a BETA, non-stable release etc.

Here is the actual shell output:

pear upgrade System_Daemon
... [more]
Failed to download pear/System_Daemon within preferred state "stable", latest release is version 0.10.2, stability "beta", use "channel://pear.php.net/System_Daemon-0.10.2" to install
Cannot initialize 'System_Daemon', invalid or missing package file
Package "System_Daemon" is not valid
upgrade failed

Regards

#138. Kevin on 17 March 2010

Twitter.com: kvz@ Gareth: Hah! sorry my mistake. I obviously meant the signals.php example:
http://github.com/kvz/system_daemon/blob/master/examples/signals.php#L56

#137. Gareth on 17 March 2010

Gravatar.com: GarethThe new logparser.php for version 0.10.2 does not even have a call to the setSigHandler method in it. The previous version had exactly the same as I had, ie array('System_Daemon','defaultSigHandler');

#136. Kevin on 17 March 2010

Twitter.com: kvz@ Nathan: Thanks : )

@ Gareth: Looking at the code samples you've provided so far, I only see you routing signals to the default handler, instead of your own. Did you have a look at the logparser example? It shows you how to route signals to your own functions.

@ Menderezz: Monit can look at pid file & check if the socket is open. I don't know but maybe that's already enough for your purpose? Check this sample config:

check process mysql with pidfile /var/run/mysqld/mysqld.pid
start program = "/etc/init.d/mysql start"
stop program = "/etc/init.d/mysql stop"
if failed host 127.0.0.1 port 3306 type tcp then restart

#135. Menderezz on 17 March 2010

Gravatar.com: MenderezzHey Kevin, thanks for the reply, the /etc/init.d/app_name stop/start.... actually works, the problem I was having was that my code wasn't checking this:

if (!System_Daemon::isDying())


it is a socket application that awaits connections and that's why it was timing out when I tried to stop, so I made a checkup in the script so before it starts to listen again, it will check if it's time to sleep :D

All I have to do now is to make this code report it's status, so I can at least use MONIT and restart it, if it stops for some reason.

#134. Gareth on 16 March 2010

Gravatar.com: GarethFunny thing is even using SIGTERM or any other signal constant I can think of in the signal handler option it still does not allow my own script to control its termination and just kills the daemon outright :(

#133. Nathan on 15 March 2010

Gravatar.com: NathanGoogled "PHP daemon", and this was the first result. Couldn't be happier. Thanks for the help!

#132. Kevin on 15 March 2010

Twitter.com: kvz@ Austin B, Bucanero, Gareth:

Hey guys: "Version 0.10.2 of System_Daemon has been successfully released, and its promotion cycle has started."

I hope this fixes all of your issues. Please come back to me if it doesn't, and thanks for your time reporting this!

#131. Austin B on 15 March 2010

Gravatar.com: Austin B@Gareth: Updated your bug with some info check it out.

@Bucanero: I got the same error and found the cause not sure how to fix but commenting it out seemed to work. Check out the bugs listing on the Pear project page.

#130. Gareth on 15 March 2010

Gravatar.com: GarethThanks for the response. But as per the example I gave I add a sig handler to attempt to catch the termination signal bit ti doesn't seem to work:

System_Daemon::setSigHandler(SIGKILL, array("System_Daemon","defaultSigHandler"));


I have also used various different constants to try and catch the correct signal but it just seems to ignore them all.

#129. Kevin on 14 March 2010

Twitter.com: kvz@ Menderezz: Did you try overriding the signal handlers? Cause that would be the way to fly. You can use the kill command to send a POSIX signal to the application, and write a function that performs your status task when it's received.

About the init.d file not working, that's weird. If you're sure it's not your code and you're running the latest version of System_Daemon you may file a bug report against PEAR and we'll take it from there.

@ Gareth: Yes it will do that automatically, if you want any other behavior you can overrule the signal handlers to perform any task you like.
... [more]
Ah ok. About your Array,Array error; this is in the latest version? If so, please file a bug report at PEAR

@ Bucanero: Agreed, you should be able to upgrade. To troubleshoot, it would help a lot to echo which signal it is trying to bind, that doesn't work on your system.

@ Ulrich: Awesome!

@ Edmund: There's nothing like that in System_Daemon at the moment. It just does a straight forward fork of itself and that's it. You may want to look at PEAR's Fork class, or use the pcntl functions to build it yourself. If you have clear ideas on how to implement this in System_Daemon I'd be happy to review any patches you may (or may not) build.

#128. Edmund on 03 March 2010

Gravatar.com: EdmundCan this be used as a multi-threaded daemon?

I need to query a DB and each record that is returned needs to be processed individually but timing is important so I need the ability to asynchronously process each record.

If this is possible, are there any function calls specifically for this purpose?
... [more]
Thanks in advance for any info on this topic.

#127. Ulrich on 02 March 2010

Gravatar.com: Ulrichhi Kevin,

a little feedback for my issue (#107)

It works !
... [more]
the problem come from the face I use __autoload and not spl_autoload_functions(). So my autoload function is ignored after I include the Daemon file

thanks for your help.

#126. Gareth on 02 March 2010

Gravatar.com: GarethJust to add to this, essentially my daemon cannot just die. It needs to complete a cycle of processing it is busy with before it terminates. I attempted to set a sig handler but it just gave me an error of:

Can only overrule on of these signal handlers: 'Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, 1, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array, Array'


My code now is :

[code="php]
require_once("System/Daemon.php");

System_Daemon::setOption("appName", "name");
System_Daemon::setOption("appDescription", "Description");
System_Daemon::setOption("authorName", "Name");
System_Daemon::setOption("authorEmail", "mail@mail.com");

System_Daemon::setSigHandler(SIGKILL, array("System_Daemon","defaultSigHandler"));

if (!System_Daemon::isInBackground() && !System_Daemon::isRunning())
{
$init_path = System_Daemon::writeAutoRun(true);

System_Daemon::start();

$sleep_time = 5;


while (!System_Daemon::isDying())
{
//Code to run per loop
}
System_Daemon::notice("Termination signal recieved, exiting");
}
[/code]

#125. Gareth on 02 March 2010

Gravatar.com: GarethI am currently having a problem where I create init.d files and then have my while loop do a check for isDying() but the daemon seems to exit as soon as an /etc/init./daemon_name stop is sent instead of when the script stops itself.

if (!System_Daemon::isInBackground() && !System_Daemon::isRunning())
{
$init_path = System_Daemon::writeAutoRun(false);

System_Daemon::start();

$sleep_time = 5;


while (!System_Daemon::isDying())
{
//App code here
}
System_Daemon::notice("Termination signal recieved, exiting");
}

#124. Bucanero on 01 March 2010

Gravatar.com: BucaneroKevin, actually I downgrade to 0.9.2 and it works ...

I will like to stay up to date, how can I troubleshoot this on my dev servers, any clues what to look for first ?

And again, thanks for your great work
... [more]
Bucanero

#123. Menderezz on 01 March 2010

Gravatar.com: MenderezzHey Kevin, this Pear package is wonderfull, and it's exactly what I needed. However I have a question.
When the php script gets started as a daemon, and if it has the command to autocreate the script in /etc/init.d/app_name it's not showing the status of the daemon. For my example, it says that app_name is stopped.

The question is: is it possible and how, to make the php daemon report it's state, if it's working or not, and I always have to "kill -9 PID" the "/etc/init.d/app_name stop" command doesn't work and it times out.

... [more] Once again, this project is just perfect, I only need some help with mentioned things.

Cheers!

#122. Kevin on 28 February 2010

Twitter.com: kvz@ Bucanero: Did a lot of fixes to signal handling in 10.1. Are you running the latest version?

#121. Bucanero on 28 February 2010

Gravatar.com: BucaneroHello Kevin, again I'm having some issues deploying this on 2 new servers

I'm getting the following error on the logs:

[Feb 27 19:03:32] info: Changed identify to 'daemon':''
... [more] [Feb 27 19:03:32] warning: [PHP Error] pcntl_signal(): Error assigning signal [l:1289]
[Feb 27 19:03:32] emerg: Unable to reroute signal handler: 0 [l:1293]

Any clues ?

Thanks

Bucanero

#120. Kevin on 26 February 2010

Twitter.com: kvz@ David James: You've given the answer yourself: Signals :)
Checkout the signal handling stuff.
Or just let system_daemon generate an init.d script and and let that send the POSIX signals for you.

#119. David James on 26 February 2010

Gravatar.com: David JamesThis package is fantastic. We are currently using it for a notification service (monitors activity in a log table and sends out alerts by subscription) and for a social media feed service (polling Gnip and bringing Twitter posts into the application).

One question I have, is there any way to signal the daemon to shutdown or a graceful way of shutting it down, instead of kill or Ctl-C (for no-daemon variety)?? I'm thinking you could have a "flag" file that the daemon monitors, if the file is deleted then the daemon finishes up and exits. Any other ideas?

#118. Kevin on 24 February 2010

Twitter.com: kvz@ nadir: If I understand you correctly, it looks like you don't include your mysql After you start the daemon. The troubleshooting section mentions this.

Changing socket paths of your Mysql server has Nothing to do whatsoever with my PEAR class and should be avoided if you are indeed a newbie.

#117. juan on 24 February 2010

Gravatar.com: juanThank you for this.

I found it very useful!!

I'll try more and send you some feedback.

#116. nadir on 24 February 2010

Gravatar.com: nadirhi, i need your help. i am trying to create a daemon for my project and we are doing our php workks in lampp. so when i try to include mysql connections in my phpdaemon , its said as no socket found as i have stopped my default sql. i want to change my socket path from /var/run/mysql to /opt/lampp/var...
where should i do that??
pls help.... its quite urgent too..
(sorry i am a newbie,excuse my mistakes)

#115. Kevin on 24 February 2010

Twitter.com: kvz@ Peter: I think I found & fixed what you ran into!
It's in this commit:
http://github.com/kvz/system_daemon/commit/e82ba977cc71cf490f4ede4f58f2be30a757f6e9
and will be part of the next release.
If you can't wait just could download the source files directly from github, but remember to download all of them as they are dependent & I changed some more things in them

#114. Kevin on 21 February 2010

Twitter.com: kvz@ Urda: Well you can easily follow the github repository to see my commits.
Was there anything in particular you wanted to see comitted?

@ Peter: Does this happen during a restart or something?

... [more] @ Ben: What if you don't set the SIGCONT handler?

@ helpful guy: Thanks, and there is no way to have the different pid location? Cause yours creates problems on itself (related to permissions, it needs to be inside an owned subdirectory)

@ Ulrich: __autoload functions are stacked. So if System_Daemon's can't load your class, the autoload function that was registered before that is called. Maybe somehow our autoloads conflict. You could add debugging information to the Daemon.php file inside the static public function autoload($className) function, and in yours, to see what paths are traversed in order to include the classfiles.

@ Diana: You could have a look at node.js, seems perfect for what you are trying to achieve.

@ Urda: You should be able to do that, something is wrong. Do you have more debugging output?

@ Warren Trucker: Any chance you have more details on that, or maybe you can share your code somewhere?

@ bertoli: You should run it as root, not sudo, but thanks for sharing!

#113. sameer on 21 February 2010

Gravatar.com: sameerreally explained in max elaborate manner

#112. bertoli on 14 February 2010

Gravatar.com: bertoliumm... solved, it was in fact a permission issue.

I did a:

chmod a+w /etc/init.d
... [more]
so the init.d file for the script was sucessfully written. Later changed back to:

chmod go-w /etc/init.d

to keep persions as before...

#111. bertoli on 13 February 2010

Gravatar.com: bertoliI am getting an error on the log file when I try to get the 'init.d' generated:

Directory: '/etc/init.d' is not writable. Maybe run as root?
Unable to create startup file. [l:835]
unable to write init.d script
... [more]
my 'etc/init.d' directory is:

drwxr-xr-x 2 root root 4.0K Feb 10 20:25 init.d

my script is root owned, as I did:

chown root myscrip.php

I also used: sudo to run the script but same error got and init.d is never generated...

any suggestion?

#110. Warren Tucker on 08 February 2010

Gravatar.com: Warren TuckerI used the system daemon not so long ago, one thing that happened was the daemon started outputing to the screen bad file discriptor.

#109. Urda on 03 February 2010

Gravatar.com: UrdaHow can I use System_Daemon::log inside of a function?

I get FATAL ERROR: CALL TO UNDEFINED FUNCTION if I try that. How can I get around this and still log to the system Daemon?

#108. Diana on 02 February 2010

Gravatar.com: DianaHello

I would like to help me or guide me, my question is this I hear dmonio create a port and turn the information as received by the port to be stored in a database or text file. Any of you could guide me? Se los agradeceria enough, I thank you very much Greetings advance Diana

#107. Ulrich on 27 January 2010

Gravatar.com: UlrichHi Kevin,

Congratulations for System_Daemon, great job !

I have encountered an issue, maybe stupid, but I can't find why.
... [more]
I try to use System_Daemon inside my class system which used __autoload() to get the classes. I need to because of our environment

But if I call a class right after the require_once "System/Daemon.php", even if the deamon is not started, I can't call any of my classes. Is that something wrong (I mean, using Daemon and __autoload?)

#106. helpful guy on 26 January 2010

Gravatar.com: helpful guyservice mydaemon status
wasnt working for me on fedora 9

I added the option
"appPidLocation" => "/var/run/mydaemon.pid"
... [more]
and removed the arbitrary restriction from
/usr/share/pear/System/Daemon.php in _isValidPidLocation where it does an arbitrary check to force the pid file to a location which isnt checked by /etc/init.d/functions 'status' function.

Anyway, now it works great :)

#105. Ben on 18 January 2010

Gravatar.com: BenI'm encountering a problem when running a simple daemon. I've included the code below. When I start the daemon with ./dtest.php, it runs and appears to fork properly. The problem is when I attempt to exit or logout of my terminal. It just hangs. If I kill dtest.php from a separate terminal, the first closes immediately. Any ideas what could be causing this?

[code=dtest.php]#!/usr/bin/php -q
<?php
require_once "System/Daemon.php";
System_Daemon::setOption("appName", "Daemon_test");
// Overrule the signal handler with any function
System_Daemon::setSigHandler(SIGCONT, array("System_Daemon",
"defaultSigHandler"));
System_Daemon::start();

while (!System_Daemon::isDying()) {
System_Daemon::iterate(3);
}

// Shut down the daemon nicely
// This is ignored if the class is actually running in the foreground
System_Daemon::stop();
?>[/code]

#104. Peter on 13 January 2010

Gravatar.com: PeterWhy does the System_Daemon log this information?

notice: starting My-Daemon daemon, output in: /path/to/log/file.log
 
emerg: My-Daemon daemon is still running. exiting [l:1010]
 
info: Not stopping My-Daemon, daemon was not running


This only occurs when the same daemon script is called again, while a child process is still running. It seems non-nonsensical to me, since it acts like the parent was still running, and wants to kill it. Then right after that discovers the parent wasn't running and no longer wants to kill it.

Why is it doing this?

#103. Urda on 12 January 2010

Gravatar.com: UrdaFantastic class! Fit my need for daemons in a project of mine at work. One question though, will we be seeing any more updates soon?

#102. Kevin on 13 December 2009

Twitter.com: kvzWhat happens if you try
php ./daemon.php?

If it works, you need to chmod u+x daemon.php and maybe put /usr/bin/php in your /etc/shells and maybe put #!/usr/bin/php -q in the head of your script.

#101. David Heremans on 10 December 2009

Gravatar.com: David HeremansHello,

I'm very impressed with this article (in fact had it in my favourites to check out for a long time already...)

I decided to go give it a go now, but I can't get it to work.

It's giving me the following error:

root@server32 [/home/flexinb/public_html]# ./daemon.php
Extension './daemon.php' not present.
root@server32 [/home/flexinb/public_html]#


Any idea what might be causing this?

#100. Kevin on 06 December 2009

Twitter.com: kvz@ rana & jatrn: System_Daemon looks at the option: 'appPidLocation' the moment it writes the init.d file.
You can change it and write another file. be sure to use the latest version

#99. jatrn on 18 November 2009

Gravatar.com: jatrnrana: I had this problem too...
Check line "PIDFILE=/var/run/$NAME.pid" (in /etc/init.d/whatever). I had to manually change it to /var/run/$NAME/$NAME.pid, verify location of pid file in /var/run

#98. rana on 09 November 2009

Gravatar.com: ranahere is my code

#!/usr/bin/php -q
<?php
require_once "System/Daemon.php"; // Include the Class
... [more]

System_Daemon::setOption("appName", "ct"); // Minimum configuration
System_Daemon::start(); // Spawn Deamon!

$path = System_Daemon::writeAutoRun();
while(1)
{
sleep(5);
}

?>

why i cant start/stop the daemon using sudo /ect/init.d/ct start or stop ??

i'm using ubuntu 8.10 and daemon is running nicely using sudo ./daemon.php

#97. Kevin on 08 November 2009

Twitter.com: kvz@ Sun Location: The Troubleshooting section covers your problem

#96. Sun Location on 07 November 2009

Gravatar.com: Sun LocationThanks you very much for this !
I've try the application but I have this error : MySQL has gone away

#95. jatrn on 26 October 2009

Gravatar.com: jatrnkevin: sounds good. just let me know how to do it :)
thanks a lot

#94. Kevin on 25 October 2009

Twitter.com: kvz@ wregen & aeuglein: I don't have one yet, but there are plans to team up with System_Socket which is probably getting a revamp:
http://article.gmane.org/gmane.comp.php.pear.devel/48419
After that, life should be sweet for you guys

@ Kees: There has to be some logging or something otherwise growing going on in your code. Cause if you run System_Daemon without custom code, this does not happen.
... [more]
@jatrn: I will change the log level to DEBUG, so that you can then choose to turn off debug logging, how does that sound?

#93. jatrn on 24 October 2009

Gravatar.com: jatrnThe log of my daemon is full of:
info: phpvoices daemon received signal: child.

Since my PHP script is a constant loop (with 1 second sleep), I'm getting entry to the log every second. Is there any way to turn this notification off?

... [more] Thanks again for this package.
jatrn

#92. aeuglein on 20 October 2009

Gravatar.com: aeugleinI have to say I am also interested in the simple example "wregen" asked for! #91

#91. wregen on 18 October 2009

Gravatar.com: wregenHi, you have mentioned that one possible application of System_Daemon is : "keep your application listening (on a socket for example)".

Can you provide a simple example? This will help me a lot.

Thank you.

#90. Kees on 17 October 2009

Gravatar.com: KeesHei David,

I'm using our solution to create several daemons ( 20 + ) which communicate with each other thru spread (ipc), however, when creating more then 12 daemonson one server, it seems that the cpu usage dramaticly increases(measured thru 'top' ), is that something you are aware of, or is this something php specific ?

#89. Kevin on 09 October 2009

Twitter.com: kvz@ David: You may want to find out and see if you can use PEAR's Fork class in combination with System_Daemon to help you with that.

@ Joe: Thanks for the comments, np. Would it be possible for you to share the code somewhere? maybe pastebin? I'm having a hard time doing all this in my head. Give me something to test with and we can take it from there

#88. Joe on 30 September 2009

Gravatar.com: JoeAt last, I think I've found the smoking gun:

First, I tried putting some cleanup immediately after the main loop. Even if I send SIGTERM to the main pid, I never seem to make it out of the loop to do any cleanup. Nothing gets logged.

Second, I set up my own handler for SIGTERM. In here, I look at the value of $child which points to our child process object (wherein there is a shutdown function). However, $child is null!
... [more]
This could be a result of the process forking, and the handler is really occurring in the pre-daemon world. If that's so, how do I communicate to the other side to shut things down gracefully?

(Apologies for the multiple stream-of-consciousness posts! Maybe someone else is having the same issue though, so this might help.)

#87. Joe on 30 September 2009

Gravatar.com: JoeOK, I have to call System_Daemon::defaultSigHandler($sig) (passing in the signal that was passed to my own handler). Silly me. :)

#86. Joe on 30 September 2009

Gravatar.com: JoeAhh, I've removed the child process from the equation. Even if I never run it, TERM just won't make this pup quit.

I did try setSigHandler for SIGTERM, and my function _does_ get called, but the loop keeps on going. I guess I could set runningOkay to TRUE but this isn't an error condition we're bailing out of. :-o

Clues welcome/appreciated!

#85. Joe on 30 September 2009

Gravatar.com: JoeFirst, this is fantastic!!! (Also, this is fantastic!)

In my case I'm using this for a monitor that dips into a data store every ten seconds. The monitor launches a child process to munch on said data. Now, this process is best kept open for a prolonged period, only to be closed after 60 minutes of inactivity (although if we absolutely have to shut it down, that's fine too).

That's where the problem is, shutting it down. If I send TERM to the monitor, it won't go away until that child process shuts down. However, in the monitor, the last thing I do (once isDying() is true) is exit my loop and check for that child process. If it's around, we tell it to exit. I never get to that part though. It' s as if isDying() isn't returning TRUE after sending TERM to the daemon. Hmm ...

#84. David on 23 September 2009

Gravatar.com: DavidHi Kevin,

Good lib. Just wondering if you can give me some advice about spawning children from within the daemon. Essentially I want to start x instances of the daemon, that run (looking for jobs from a Gearman server) for the entire time the daemon is running.

This may not be the best approach. I imagine that spawning children AS work/jobs come into the daemon would be a more efficient, however I haven't been able to get that working with System_Daemon yet.

So far this is what I'm doing (and seems to be working) and I'm wondering if there are any problems with something like the following:

for($i=0; $i<3; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
exit('Could not fork children');
} else if ($pid) {
System_Daemon::log(System_Daemon::LOG_INFO, 'Spawned child: ' . $pid);
} else {
while (!System_Daemon::isDying()) {
// do something like look for a job from gearman
$gmw->work();
System_Daemon::iterate(1);
}
System_Daemon::stop();
}
}


I understand that potentially if the children exit they could become zombies, however I'm not sure if that applies in this situation as I want the children to run for the life of the parent (daemon).

Any help / guidance would be greatly appreciated.

#83. Kevin on 17 September 2009

Twitter.com: kvz@ Remiko: This should prove to be enough:

./Daemon.php
./Daemon
./Daemon/Options.php
./Daemon/OS.php
./Daemon/OS
./Daemon/OS/Ubuntu.php
./Daemon/OS/Debian.php
./Daemon/OS/Fedora.php
./Daemon/OS/BSD.php
./Daemon/OS/RedHat.php
./Daemon/OS/Windows.php
./Daemon/OS/Linux.php
./Daemon/OS/Exception.php
./Daemon/Exception.php


You could even also leave out the operating systems you're not planning on using.

But on the other hand: if you're going to need multiple files anyway, why not just add the entire dir. It will really only add a few kbs.

#82. Remiko on 12 September 2009

Gravatar.com: RemikoCould I know the minimum file lists in standalone packages to let the daemon without PEAR?

#81. Kevin on 22 August 2009

Twitter.com: kvz@ Jason: There were some bugfixes recently. What version did you try?

@ Kris: Autch.. Love your gravatar though :)

#80. Kris on 13 August 2009

Gravatar.com: KrisApparently this was caused by a wrong EOL in my php script. Using dos2unix on the daemon.php file fixed the problem... took me 3hours to find this one :-/

#79. Kris on 13 August 2009

Gravatar.com: KrisI have a weird problem. I created a daemon based on the logger example. I ran the script using ./daemon.php, then killed it with the command killall -9 daemon.php (notice the 9 not g) the process was killed, but when I try to restart the script i now get:
Extension './daemon.php' not present

I have no clue how to solve this... the script ran the first time.

#78. Jason on 12 August 2009

Gravatar.com: JasonI have installed all the required libraries and created a test which I start at the command line with php socket.php I have made a separate sub directory of the pid so that it lives in socket/socket.pid. The continue to get "socket daemon was unable to write pid file" although the script does delete the file. I recreate the file and I get the same error and the file is gone. Any thoughts on what I might do. I am running the script as root and have checked all ownership and permissions.

#77. Kevin on 12 August 2009

Twitter.com: kvz@ Peter: Have a look at
http://brian.moonspot.net/php-fork

#76. Peter on 08 August 2009

Gravatar.com: PeterKevin,

I'd like to use your class for as job scheduler daemon in PHP where I have the daemon run various jobs throughout different times of the day. I'd like the daemon to simply spawn each job in a child process and go back to being a daemon without each job running within the daemon's process. How hard would this be to do without interfering with your class?

Thanks
... [more]
How hard would it be to have some of the code running with the daemon

#75. Sean Hess on 04 August 2009

Gravatar.com: Sean Hess@Kevin - The original motivation was to get the daemon's loop to run as a separate script, since writing a loop with System_Daemon was causing strange problems. Thanks for your article and work!

#74. Kevin on 04 August 2009

Twitter.com: kvz@ Easy Daemons in PHP: I'm honored that someone build a wrapper around my wrapper : ) Haven't looked at the code yet, but if it does what you need: I'm happy.

#73. Easy Daemons in PHP on 03 August 2009

Gravatar.com: Easy Daemons in PHP[...] This class and script makes it easy to turn a one-shot php script into a daemon that runs in the background on a timer [...]

#72. Kevin on 29 July 2009

Twitter.com: kvz@ Bucanero: Ok, several ways. You can have them open a socket and see if it's still open. You can check the pidfiles (inside /var/run/) and see if the pids are still running (probably execute ps to do that), or send then POSIX signals. You can also write something to disk periodically and check that, or have a third party tool like monit monitor your process (which is probably the wisest)

#71. Bucanero on 29 July 2009

Gravatar.com: BucaneroKevin

Thanks for your reply

I figure out the "Who are you?", it was because on my box I did not have a user with uid 1000 or group with id 1000. As your example had
... [more]
Another question, How can I know from php that my daemons are running ?

Running ps uf -C from the console I can see they are running, is there a way to have this info via php ? I need to write a monitoring script

Thanks again

Bucanero

#70. Kevin on 28 July 2009

Twitter.com: kvz@ Bucanero: I don't see where 'who are you' is coming from at the moment. Considering your multiple instances question. Here's an idea:

Start your daemon with an argument like:
./yourdaemon.php a

... [more] and configure your appName at runtime to adhere the argument 'a'. Now when you write an init.d file or pidfile, 'a' will be used.
This way you can have as many daemons as you want with own logfiles, pidfiles & init.d files, but with 1 script.

#69. Bucanero on 28 July 2009

Gravatar.com: BucaneroNice Job creating this !!!

I was wondering how to create "multiple email generation daemons", My idea is to have 10 (or more if we have bigger loads) of this all the time running and looking for emails to create and send.

The problem I was encountering is that if I try to run the same file again (starting another one from the console) I receive and error message. One option is to have files from to 1 to x (example daemon1.php ... deamon2.php) do you think this make sense ? Is this the way to go ?
... [more]
Also running your example, I got 3 times on the console " Who are you?"

Thanks again for this

Bucanero

#68. Kevin on 15 July 2009

Twitter.com: kvz@ AkEdEv: Excellent, thanks for reporting. I fixed it in svn:
http://trac.plutonia.nl/projects/system_daemon/changeset/228

It will be included in the next package release.

... [more] If for follow ups on things like these you could use the official PEAR bug system, that would be awesome.

#67. AkEdEv on 13 July 2009

Gravatar.com: AkEdEvPlease check this.
I just run your example on php 5.3.0 and appears this line.

PHP Deprecated: Function eregi() is deprecated in /usr/share/pear/System/Daemon/Options.php on line 250

#66. Kevin on 07 July 2009

Twitter.com: kvzTypically you would configure a deamon to run at server boot, and have it accept jobs while it's running.

If you want to control a daemon's start / stop you typically would do that with a script inside /etc/init.d (os dependent, for some OSes, System_Daemon can generate such a script for you)

So, yes in theory you could then use a PHP script to control run the init.d script and control your daemon process. But I'd hardly recommend it because of
... [more] - bad practice
- security risks involved

#65. dulig on 07 July 2009

Gravatar.com: duligHey,
Thanks for this great article.
I think about using your daemon in my web application.
This might be a stupid question, but since the daemon can only be started out of command line, will it be possible, to do a shell_exec to start the daemon out of a web application?

... [more] Thanks in advance
dulig

#64. Kevin on 26 June 2009

Twitter.com: kvz@ jonathan: the iterate function actually uses clearstatcache() so you can also use that directly. As long as you use it.
But I'd rather have people use my iterate() function so that I can implement additional fixes as I find more issues.

@ Martijn: You could also use cron combined with solo (http://timkay.com/solo/) to prevent overlap and do what you want. If you need more control / intelligence on the other hand, you may need to fire actions and keep track of time yourself.
I have once seen a full table-based cron implementation in PHP, I'm sure you'll find it if that is what you need. Or maybe a simple

while(true) {
if (!$ranToday && date('Hi') > 1700) {
execute();
}
}

#63. Martijn on 21 June 2009

Gravatar.com: MartijnThnx, for the article. have to say it works nice and easy.

I think it's better solution then using cronjobs. Only wondering, i have to do a daily job, processing books. (about 2.000.000 records) Maybe i missing something, how to do a daily update, depending the content of a certain folder?

I'm istill depending on cron or can you give some hints to solve the problem?
... [more]
regards Martijn

#62. jonathan on 19 June 2009

Gravatar.com: jonathanRE: Statcache will corrupt your data

is clearstatcache () broken?

I've been using this successfully, but did I miss something?

#61. Kevin on 18 June 2009

Twitter.com: kvz@ Adam Charnock: It should a boolean when it already exists. And the string when it has created it for the first time. Can you confirm this?

#60. Adam Charnock on 15 June 2009

Gravatar.com: Adam CharnockHi Kevin,

This is really great work, thank you very much. We are going to be using it extensively in the backend of the next version of walltweet.org.

I did notice this:
... [more]
"On success, this will return the path to the autostartup file: /etc/init.d/logparser, and you're good to go!"

... which isn't actually correct. It seems to return boolean, not a string. Just a minor point!

Thanks again :D

Adam Charnock

#59. Kevin on 15 May 2009

Twitter.com: kvz@ vince: Yes it uses pcntl, but it's probably already enabled cause Ubuntu should have this this by default. I think you can just install the class and let me know what happens?

#58. vince on 15 May 2009

Gravatar.com: vinceHi Kevin,
thanks for the reply. I haven't yet installed the pear class because I think that I have to install first the pcntl support. But maybe it's unnecessary... Your pear class isn't based on php-pcntl functions?

#57. Kevin on 14 May 2009

Twitter.com: kvz@ James: That could definitelty work although you would have to make a bridge between web interface + (root) cli, and personally I don't have use cases for something like that. As in: I can't think of scenarios where I would want to have to manually intervene or stop daemons. They should be designed to not require that I think.

@ Mike: Sorry I don't know PHP_Fork, I only know of it.

@ mikesta: thank you :)
... [more]
@ vince: I've tested up until Ubuntu Intrepid and those all work out of the box. Can you give me some exact output/errors?

#56. vince on 13 May 2009

Gravatar.com: vinceHi Kevin,
I would like to start creating some funny daemons in php so I have installed a LAMP + php5-cli on an ubuntu 9.04 system.
But I have no support for pcntl yet! How can I do? Can you suggest me a guide?

vince.

#55. mikesta on 02 May 2009

Gravatar.com: mikestaYou did a good job, keep ahead!

#54. James on 01 May 2009

Gravatar.com: JamesMike, it's back up now. If it's down the next time you try, I'll post a link to a copy of that code that I just snagged for backup purposes.

#53. Mike on 30 April 2009

Gravatar.com: MikeUpdate - I was able to get php_fork running on my server. I did not have the shared memory module installed for PHP - duhhh. I'm going to continue testing that.

Thanks for your help!

#52. Mike on 30 April 2009

Gravatar.com: Mike@James - that link to bipinb.com appears to be dead - nuts, I wanted to look at that.

@Kevin - I looked at that php_fork PEAR package. I'm pretty new to PEAR, but I couldn't even get the basic.php to run - doesn't even throw an error I can diagnose.... I know PEAR is good on my server as I'm able to execute your sample code fine.

Thanks very much for any help you can provide, but I don't want to be a bother...

#51. James on 30 April 2009

Gravatar.com: James@Kevin & @Mike: There is some code from ~2008 that looks like it forks off children pretty elegantly: ( http://bipinb.com/making-php-program-as-daemon.htm ). I have not actually executed the code, however, so don't know for sure.

To control those forked daemons, it seems possible to do the following: insert each daemon's PID into a MySQL table, and have each daemon update MySQL every several minutes informing you of what it's up to. You could then see what's going on with each daemon child via a browser interface, and kill the child if needed.

At least, in my head, that makes sense. But I haven't committed those thoughts to code.

#50. Kevin on 29 April 2009

Twitter.com: kvz@ James: You noticed correctly :) Thanks. If you have any specific ideas on System_Daemons future feel welcome to submit them.

@ Mike Stackhouse: I've found an unmaintained PEAR package: Fork. Maybe that can do what you want. I didn't have plans to make this a system_daemon feature as I've always felt that it should be a simple and basic building block. What do you think?

#49. Mike Stackhouse on 27 April 2009

Gravatar.com: Mike StackhouseNice article - I've tested your sample code on our FreeBSD 7 server.

We have the requirement to have a daemonized server process that would fork off children based on control records in a database. Does your class have functionality to fork off children, keep track of their process id's and kill them if need be?

Still trying to wrap my head arounc pcntl - I might be over-thinking the problem. Could it be as simple as implementing in a database reading loop, and when a new child is needed execute the fork at that time? There are some good examples on the web for managing child processes from that point forward - this one seems to make sense - http://www.van-steenbeek.net/?q=php_pcntl_fork.
... [more]
Might you know of any examples that would have functionality such as we require?

Thank you very much!

#48. James on 25 April 2009

Gravatar.com: JamesI noticed you added version 0.8 alpha to the PEAR repository today. This is some very promising stuff. Keep up the great work!

#47. Tech Blog on 20 April 2009

Gravatar.com: Tech BlogGreat post thanks, I learned something new about PHP today :)

#46. Kevin on 19 April 2009

Twitter.com: kvz@ Saso: Currently your daemon can make iterations without my class executing one line of code. So self monitoring would require my users to call for example:

while (true) {
System_Daemon::ping();
// your code
}


That way I could implement self checks from within the ping method, depending on the configuration you specify.

It could be an interesting addition. As far as advanced communication goes. You could look into Net_Socket (also pear) and/or go for TCP/IP.

Another method would be a central memcached server or actual shared memory using shmop (but that's limited to 1 machine).

Non of these things and methods are standard in System_Daemon however. It merely provides the most fundamental brick for others to build upon.

But if you like to share what you've come up with, give me a ping. I'm not sure yet but maybe we could generalize it and add a little sauce on top of the daemon.

#45. Saso on 19 April 2009

Gravatar.com: Saso@Kevin:
Well, it doesn't help me much :)
Probably I will use Ur project and upgrade it with my ideas and send it back to U, for U to make world use of it :)
I would need sync and async communication between processes, so front-end and daemons can 'talk' with each other. Self-observing would also be necessary, to avoid wild daemons eating resources.
I, for example, need this to make chat bot, which will be daemonized and frontend interfaces (IRC, PHP, what-ever..) will ise it for 'chat API'.
... [more] This is great to avoid the overhead of creating and killing all the objects in heavy front end.
But I agree, for mass mailing, writing to DB is enough.
Regards, Saso

#44. Kevin on 19 April 2009

Twitter.com: kvz@ Yılmaz Uğurlu: Great to hear!

@ Janitha Karunaratne: An ideal daemon in an ideal world would not be written in PHP, I make that clear in the article already. But you actually make it sound immoral :D

Don't be alarmed.. My house is built with good old bricks: not forks & spoons. And yes some of my daemons are created with PHP. Why? Because it works. Because I can use my existing classes and take away load from front-end processes built on the same technology.
... [more]
I feel like using 4 different languages to solve 1 problem is really about creating 1 thing and 1 thing only: a maintenance hell.

If I am to redo my existing classes in C (or perl or python), I will have to duplicate my patches & improvements for the rest of my programming career...
To justify this decrease in productivity there would have to be some very convincing reasons for that. And your (funny but) dogmatic metaphor is not going to cut it.

I don't believe you're not basing your opinion on actual results.
I have PHP daemons running for over 2 years now without a problem. I understand you may get an unary feeling but I'm pragmatic and this is actually working very well.

Anyway, nobody is forcing you to use this, so Happy compiling :)

@ Saso: You could work with a database queue, storing heavy jobs and having daemons eat them away using the same DB class as your frontend process.
Deamons are already limited to 1 per 'appName', and for simple communication you could use POSIX signals. Does this help you out a bit?

#43. Saso on 18 April 2009

Gravatar.com: SasoHi, Kevin, great article.
I am searching for IPC (Inter Process Communicating) for using with Ur Daemon.

I would like to change architecture of my app. to lighten frontend and have heavy duty daemons to do all the work.

... [more] What I find missing (from my point of standing) is automated limiting daemon loops, number of daemons and some mechanism for maintaining pre-forked processes, ready to use (similar as Apache2).
This is needed just due bad PHP-coding practices, to avoid leaked code eating all resources.
And I miss Remote Procedure Call, as stated above: It would be great to have daemoned API, which we 'just use' in our PHP frontend.

Regards, Saso
ps: dont get me wrong, Ur work is just great, I just give U some new ideas.. :)
(aka. being lazy-constructive)

#42. Janitha Karunaratne on 16 April 2009

Gravatar.com: Janitha KarunaratneUsing PHP to do small quick tasks is ok, it's good for rapid development of websites, but it's quite unfit for purposes such as writing service scripts that run in the background.

PHP is meant to be started quickly and killed quickly (such as a page view) and that's what it's memory management is optimized for for the duration of the script... if you run it for prolonged periods of time, expect some seriously nasty memory usage and leaks.

Your reasoning for this is that everyone knows it and it's availability everywhere... this is where I have to disagree. That's like saying "Hey, lets build this house using spoons and forks, because everyone knows how to use them and their everywhere!". It's possible, but it's a very poor choice.
... [more]
Just because it's the only thing a person knows or just because it exists everywhere doesn't make it the proper tool to use.

#41. Yılmaz Uğurlu on 13 April 2009

Gravatar.com: Yılmaz UğurluThank you, the daemon now runing indefinitely.
But i still didn't create startup script correctly. I tried mant things, i guess i have problem with my ubuntu box, whatever.

I wrote feed crawler daemon for test. It's fecthing and writing feed items to databse. I watched very long, and everyting went well. Cpu usage, memory usage, all my concerns are gone. Thank you so much this is really great application.

#40. Kevin on 12 April 2009

Twitter.com: kvz@ Yılmaz Uğurlu: Sorry my bad, fixed in SVN now as well.

It looks though as if you really really don't have permission to write anything to init.d

What if you 'su -' first and then really run it as root instead of sudo-ing it?

About the 3 times thing. Are you using the logparser example? That shuts down because it's only a test.

If you just put a

while(true) {
// Your code here
sleep(5);
}


It should run indefinitely. Unless you run into any problems like stated in the troubleshooting section

#39. Yılmaz Uğurlu on 12 April 2009

Gravatar.com: Yılmaz UğurluThanks Kevin. I tested,

First:
in OS.php line 297 and line 299 must be self::isWritable(...)
because i get this error fist:

Fatal error: Call to undefined function is__writable() in /usr/share/php/System/Daemon/OS.php on line 297

and i changed these lines.

So, after i run my daemon just like: sudo ./myDaemon.php
It went well but, when i looked at the log file i showed these errors
[Apr 12 17:04:31]  warning: [PHP Error] fopen(/etc/init.d/130827514849e1f4ef90c8b.tmp): failed to open stream: Permission denied [l:303]
[Apr 12 17:04:31] notice: Directory: '/etc/init.d' is not writable. Maybe run as root?
[Apr 12 17:04:31] warning: Unable to create startup file. [l:761]


I have one question more, i didn't add the System_Daemon::stop(); line to end of my file.
Bu after 3 times loop my daemon is stopped. i guess i didn't understand how to write endless daemon, how can i do that?

#38. Kevin on 12 April 2009

Twitter.com: kvz@ Yılmaz Uğurlu: On that link, click on Download in other formats: raw, and overwrite it in (probably) /usr/share/php/System/Daemon/

#37. Kevin on 12 April 2009

Twitter.com: kvz@ Yılmaz Uğurlu: Thanks for testing. I've improved the method for is_writable and hope that will help avoid your bug. The fix is in the OS.php file. The new version can be found here:
http://svn.plutonia.nl/projects/system_daemon/browser/trunk/System/Daemon/OS.php

Are you able to confirm this works? If so than I can release a new PEAR package for System_Daemon

#36. Yılmaz Uğurlu on 11 April 2009

Gravatar.com: Yılmaz UğurluHi Kevin, i tested and it's working great.
I have question about startup file. I'm runnig as root my script, after the start i'm checking log file, all script start's has this two line.

notice: Directory: '/etc/init.d' is not writable. Maybe run as root?
[Apr 11 12:23:56] warning: Unable to create startup file. [l:761]


But i'm running script as root, what i'm doing wrong?

#35. anon on 07 April 2009

Gravatar.com: anonhttp://dev.pedemont.com/sonic/

a php daemon, with plugin type arch.

#34. Kevin on 03 April 2009

Twitter.com: kvz@ ger: I am not able to reproduce that behavior. Maybe you can dump all get_defined_vars so make 100% sure nothing is increasing?

#33. ger on 02 April 2009

Gravatar.com: gerI have jabber (XMPP) php daemon running which sends news updates to the users who has subscribed to them.
The only thing I can say from my experience - php seems have memory leaks when works in infinitive loop. Even if he php code itself is well designed to pervent this. If you'll monitor the memory consumed by your php daemon - you will see it continuously grows in time.
The solution of this prob I use - juts kill / restart the daemon with cronjob from time to time.
Hope this will be useful for someone.

#32. Dani on 25 March 2009

Gravatar.com: DaniGreat, I guess I will be able to get some of my php scripts out of their uggly cron configuration. When I needed to run a script every 15 seconds I had it run it 4 times in cron with different sleep times (0, 15, 30 and 45 secs) which is a very uggly thing to do (and 'dangerous' if the script cannot handle concurrent execution).

Sometimes PHP can be the ideal choice to run such things. If you have some LAMP environment with PHP handling your data in the first place and you need some background process it is the best choice to use the same environment for that process instead of risking to corrupt your data because of compatibility issues like character-encoding.

#31. Kevin on 16 March 2009

Twitter.com: kvz@ jatrn: Please upgrade to the latest version of System_Daemon, and try again. Now what does your logfile say?

@ rhuel: This is not going to work on shared-host-environments, because you need to be root to fire up the daemon. Only after you start it, it can become another user.
This is because root will have to setup some dirs like logdir & rundir, and chown it all.

#30. rhuel on 16 March 2009

Gravatar.com: rhuelYour code works and it rocks. Problem is my webhost has php without --enable-pcntl compiled. Can we go around this requirement?. I need it to run in background. Thanks.

#29. jatrn on 11 March 2009

Gravatar.com: jatrnHello,
First of all thank you very much for this lib, it is very usefull.
I got a small problem. I'm able to start my daemon by "/etc/init.d/IMM15 start" but can not stop it, "/etc/init.d/IMM15 stop" doesn't work. There is nothing in the log and on the screen. See my code below.

Thanks for you help.
... [more]
#!/usr/bin/php -q
<?php
require_once "System/Daemon.php";
System_Daemon::setOption("appName","IMM15");
System_Daemon::setOption("appDescription","simple deamon by jatrn");
System_Daemon::setOption("authorName","xxx");
System_Daemon::setOption("authorEmail","xxx@yahoo.com");

System_Daemon::start();
System_Daemon::writeAutoRun();

while (true) {
$t=1;
sleep(10); }
System_Daemon::stop();
?>

#28. Kevin on 04 March 2009

Twitter.com: kvz@ Eduardo Jordan: Thanks!

#27. Eduardo Jordan on 03 March 2009

Gravatar.com: Eduardo JordanHere we go again. PHP sucks? Is it horrible language?
I wonder why facebook, a multibillon dolar company, uses it!
Kevin, I gonna use this class and will give you feedback.
About the perl guy. FYI, PHP has syntax similar to Perl, just simpler to understand.

... [more] I guess that for Perl programmers:

my @lines = <FILE>;
while (<FILE>) { print $_; }

that is nice, and this horrible

$handle = fopen('datafile.csv', "r");
while (!feof($handle)) {
$buffer = fgets($handle, 4096);
echo $buffer;
}
fclose($handle);

I don't think so, second one is easier to read and understand.

#26. Kevin on 02 March 2009

Twitter.com: kvz@ Anon: Thanks for your comment. It is clear that you do not want to use PHP for this.

Let me just say: Nobody is forcing your hand here.

But I think your vision on this matter does not include factors like: time, resources, and company context.
... [more] For instance at my company, there is no (need for a) C programmer at all. There never was and there probably never will be. But we still have the need to automate a lot of thinks that are based on our PHP software.
Perl just doesn't play well with our LAMP environment. For instance we have many libraries & classes that the automating daemons need to interface with. And I was not planning to recreate & maintain all of our business-logic (no, this is not in CPAN unfortunately ;) in two different languages. I value DRY principles too much for that.

So I've been running PHP daemons for years now (it took a while before I submitted to PEAR) and without any problems. And so for me it's safe to say: it solves more problems than it creates.

#25. Anon on 01 March 2009

Gravatar.com: Anon@Kevin

Hey, Anon here (the one you responded to). I seemed to stumble upon this post again~

Let me reemphasize that it is interesting that PHP can do this, but for obvious reasons it should not. PHP is an awesome language in which quick websites can be easily created due to it's ease of use and availability.
... [more]
Other than than, to put it bluntly, it sucks. It is truly a horrible language. There is little point in debating that point here so please don't. (If you really want to debate, use a search engine to find essays about PHP and it's..erm..attributes.) (I am kind of cheating here; I go on to insult PHP and tell you not to argue :O)

I suppose when you have a hammer everything looks like a nail, but your three reasons to use PHP for creating daemons are not convincing at all.

"Reuse & connect existing code"
You should not be reinventing the wheel to begin with. If you must, there is Perl and CPAN.

"Deliver new applications very fast"
Yes, PHP has a lot of functions (too many), but Perl is better at creating applications quickly.

"Everyone knows PHP (right?)"
I already mentioned this point in my previous post, but I will do so here again (with a different approach). If your C programmer leaves, find a new C programmer. It is really that simple. If your Photoshopping person left would you resort to using Microsoft's paint? No, you would get a new Photoshopper. (Hypothetical situation is hypothetical, by the way.)

#24. Centerax on 13 February 2009

Gravatar.com: CenteraxWow!

This is great stuff, in conjunction with Monit this is very powerful and easy to implement.

Great job!

#23. Kevin on 11 February 2009

Twitter.com: kvz@ Chris: No I didn't. That's quite shameless. Most of the times they have the decency to at least add a small note as to who they got it from.

I've left a comment at that URL.. Let's see how long it stays there ;)

Thanks a lot for letting me know Chris!

#22. Chris on 10 February 2009

Gravatar.com: ChrisDid you know this has been published verbatim here: http://www.hurricanesoftwares.com/how-to-create-daemons-in-php/

#21. Ali on 10 February 2009

Gravatar.com: AliEpic post! I was looking for a way to use a daemon to create an automated backup system and this is just what we needed!

#20. Kevin on 01 February 2009

Twitter.com: kvz@ Tom: Yes, I haven't made anything with it yet, but it's very cool that's all possible :)

#19. Kevin on 01 February 2009

Twitter.com: kvz@ Strawp: Yes that's not really what this class was designed for. Maybe you could look into PHP_Fork (http://pear.php.net/package/PHP_Fork) which I believe does something similar. Good luck!

#18. Tom on 27 January 2009

Gravatar.com: TomReally cool! Did you also know about php-gtk? You can use PHP to make desktop application as well. PHP is really a great language for it's convenience. I wouldn't go and make Photoshop with it...but for small applications -- most definitely -- especially if people are accepting things like AIR as "applications". Great work, thanks!

#17. Strawp on 26 January 2009

Gravatar.com: StrawpThis looks great!

Quick stupid question though: In your example above, is everything from ::start(); to the end of the script the child process? Is the parent dead at this point?

If for example I wanted to fork a slow script as a child from the action page of a web app but keep the parent running so that it could finish up and redirect the user, how would that look?

#16. Kevin on 25 January 2009

Twitter.com: kvz@ all: thanks for the kind words

@ marek: That's not an issue.. Thats the solution TO the issue that you will lose the mysql connection if you don't.

#15. Douwe Kasemier on 23 January 2009

Gravatar.com: Douwe KasemierBrilliant pear plugin. Using it for multithreading!

#14. Zach Blank on 21 January 2009

Gravatar.com: Zach BlankThis looks amazing! I will be using it for some live data collection and visualization at a party in NYC this weekend. Thanks for sharing!

#13. Jason Moss on 20 January 2009

Gravatar.com: Jason MossGlad to see other people recognize the use of PHP for non-web use. We've been using it for some command-line based applications that work quite nicely. Development especially is nice, with the massive amount of built-in functionality and the outside resources available. I use PHP a ton, but I haven't done any web dev :P

#12. Dustin on 20 January 2009

Gravatar.com: DustinYeah first post stumble - sorry for being dumb - i like this post.

#11. marek on 20 January 2009

Gravatar.com: marekhow to fix issue "Connect to MySQL after you start() the daemon" ?

#10. Timothy on 19 January 2009

Gravatar.com: TimothyWow. That's awesome! Thank you!

#9. wiwo on 14 January 2009

Gravatar.com: wiwoThank you for your post. It is really interesting. I didn't know one can create deamon with php! Not yet tested but when I have the need I would know where to go :)

#8. Kevin on 13 January 2009

Twitter.com: kvz@ Matt Baker: Thank you for correcting me :)

I suppose I forgot to say the obligatory:
Sorry for my bad English, it's not my native language.

... [more] But really, thanks. I want to improve my English and I will definitely take a look at it.

#7. Kevin on 13 January 2009

Twitter.com: kvz@ crackgerbal: Thank you!

@ simeon: I agree PHP is not the best language for it, the article says something similar. But it's very well possible and even suitable in some cases.

From a design point-of-view you may be right about PHP. It probably wasn't meant to run that long, but:
... [more] - I haven't run into problems yet
- I believe PHP resource IDs are different from file descriptors

You do make in interesting point though: thank you.

#6. Kevin on 13 January 2009

Twitter.com: kvz@ Anon: Yes (because it's so easy) there are a LOT of PHP coders, and obviously there are a lot of rookies as well. And some may even never get passed that point.

But to do any real damage you would need root access to a Linux box in a production environment.
If you do: I hope you're at least responsible enough to know your own coding limits and not run your hobby projects on your company's main server. If you're not: your company's box is probably already destroyed, anyway. along with your job :)

#5. Matt Baker on 13 January 2009

Gravatar.com: Matt BakerYou use too many commas. Mostly in incorrect places.
http://owl.english.purdue.edu/handouts/grammar/g_comma.html

#4. simeon on 12 January 2009

Gravatar.com: simeonYour work to create the System_Daemon class is impressive. Unfortunately PHP is just not the best language to do this sort of thing. One recent article in my feeds noted that PHP leaks file descriptors (see http://gnuvince.wordpress.com/2008/10/28/php-wrong-for-long-running-processes-wrong-for-america/). This means that long running PHP processes eventually are unable to open files...

PHP's process model was is inherited from the cgi days and is built around loading, executing, and terminating (and don't get me wrong. There are definitely advantages to this process model for web development). Running a PHP script indefinitely is likely to push up against the edge cases in the runtime engine...

The alternative approach I've taken when I need something more sophisticated than cron jobs is to make sure I have command line interfaces to my PHP business logic and write the daemon in python or even bash. The daemon can be extremely simple (listen on a port, tail a file, etc) and merely invokes the appropriate PHP script to handle all the business logic... Just my 3 cents.

#3. Anon on 12 January 2009

Gravatar.com: AnonOh, err, I didn't mean that YOUR code was the horrible PHP code that was littered throughout the web, I just meant in general ;D

#2. crackgerbal on 12 January 2009

Gravatar.com: crackgerbalAwesome blog! I went from not knowing what a daemon is to being able to write my own in php. great post!

#1. Anon on 12 January 2009

Gravatar.com: AnonI read your article and it did a great job of explaining daemons and such in an easy to learn way. However,

"Everyone knows PHP (right?)"

Everyone knows how to grunt and point too. Sure, I find it interesting that PHP can do this, but please, there is horrible PHP code littered throughout the web. Please do not bring that to a lower level :(