Skip to content

Instantly share code, notes, and snippets.

@lcherone
Last active November 27, 2021 11:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lcherone/28b92af0f06c1224b30fe734a0d51877 to your computer and use it in GitHub Desktop.
Save lcherone/28b92af0f06c1224b30fe734a0d51877 to your computer and use it in GitHub Desktop.
CRON PHP Daemon
#!/usr/bin/php
<?php
/**
* Need to test code works on ©Win"virus"dow$
*
* Aim:
* To run code within a cron task at a settable frequency above 1 per minute,
* but not overrun the minute or run again if already running, tasks should
* also complete at their own pace within the minute.
*
* Solution:
*
* Controlling state:
* Define the state by setting a variable as false, look for a pid file,
* if the pid file is found but the variable is not running, assume the script
* died prematurely, attempt to kill the process, write new pid to file.
*
* Code iteration frequency:
* Using a while loop watch the time() + 60 !> time() this makes it much
* simpler to define our sleep time and turns time back into a frequency rather
* then a calculation.
*
* Setup cron to run every minute (brakes if task breaks):
* * * * * * /usr/bin/php /home/lozza/cron.php
* Setup cron to run at start but continue to run (restarts if task breaks - watchdog):
* @reboot while sleep 1; do cd /home/lozza && /usr/bin/php cron.php ; done
*/
class pid
{
protected $pidfile;
public $running = false;
public function __construct($directory = '')
{
$this->pidfile = (!empty($directory) ? $directory.'/' : null) . basename($_SERVER['PHP_SELF']) . '.pid';
if (is_writable($this->pidfile) || is_writable($directory)) {
if (file_exists($this->pidfile)) {
$pid = (int) trim(file_get_contents($this->pidfile));
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$wmi = new COM("winmgmts:{impersonationLevel=impersonate}!\\\\.\\root\\cimv2");
$procs = $wmi->ExecQuery("SELECT * FROM Win32_Process WHERE ProcessId='".$pid."'");
foreach ($procs as $proc) {
$proc->Terminate();
$this->running = true;
}
} else {
if (posix_kill($pid, 0)) {
$this->running = true;
}
}
}
} else {
die("Cannot write to pid file '{$this->pidfile}'. Program execution halted.\n");
}
if (!$this->running) {
file_put_contents($this->pidfile, getmypid());
}
}
public function __destruct()
{
if (!$this->running && file_exists($this->pidfile) && is_writeable($this->pidfile)) {
unlink($this->pidfile);
}
}
}
$pid = new pid(dirname(__FILE__));
if ($pid->running) {
exit;
} else {
$stopTime = microtime(true) + 60;
$i = 1;
while (microtime(true) < $stopTime) {
// time iteration as not to be running when next cron runs ...
$loopStart = microtime(true);
### do your code
//echo $i.PHP_EOL;
$i++;
// stop if next task will overrun minute
if ((microtime(true)+(microtime(true) - $loopStart)) > $stopTime) {
break;
}
// Run 943995 times within the minute = usleep(1000) = slow but dont 100% CPU
usleep(1000);
// without!
// Run 19037412 times within the minute, but 100% CPU
//usleep(0);
}
echo 'Run '.$i.' times within the minute'.PHP_EOL;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment