Skip to content

Instantly share code, notes, and snippets.

@zandzpider
Created September 18, 2014 11:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zandzpider/98c434a8dc71dbfc43bf to your computer and use it in GitHub Desktop.
Save zandzpider/98c434a8dc71dbfc43bf to your computer and use it in GitHub Desktop.
<?php
/*
* https://gist.github.com/andergmartins/5066143
* From: http://abhinavsingh.com/blog/2009/12/how-to-use-locks-in-php-cron-jobs-to-avoid-cron-overlaps/
*/
class CronHelper
{
const LOCK_DIR = '/tmp/';
const LOCK_SUFFIX = '.lock';
const LOCK_AGE_MAX = 3600;
private $pid = false;
private $file = false;
private $locked = false;
/**
* @param string $file optional
*/
function __construct($file = '')
{
$this->initialize();
global $argv;
if (!$file && is_array($argv))
{
$file = implode('.', $argv);
}
$this->file = self::LOCK_DIR.$file.self::LOCK_SUFFIX;
}
/**
* @return bool
*/
public function isRunning()
{
if (!$this->pid)
{
return false;
}
$pids = explode(PHP_EOL, `ps -e | awk '{print $1}'`);
if (in_array($this->pid, $pids))
{
return true;
}
}
/**
* @return bool|int
*/
public function lock()
{
// unlock needs to be called before a new lock can be done
if ($this->locked)
{
error_log("==$this->pid== Already locked, please wait...");
return false;
}
if (file_exists($this->file))
{
$file_age = (time() - filemtime($this->file)); // in seconds
// Is running?
$this->pid = file_get_contents($this->file);
if ($this->isRunning())
{
// check for staled locks
if ($file_age > self::LOCK_AGE_MAX)
{
error_log("==$this->pid== Lock staled. Killing PID! Age: $file_age / ".self::LOCK_AGE_MAX." (Seconds)");
// kill the running script
exec('kill -9 ' .$this->pid);
$this->unlock();
return $this->lock();
}
error_log("==$this->pid== Already in progress...");
return false;
}
else
{
error_log("==$this->pid== Previous job died abruptly...");
}
}
$this->pid = getmypid();
file_put_contents($this->file, $this->pid);
error_log("==$this->pid== Lock acquired, processing the job...");
$this->locked = true;
return $this->pid;
}
/**
* @return bool
*/
public function unlock()
{
if (file_exists($this->file))
{
unlink($this->file);
}
if ($this->pid)
{
error_log("==$this->pid== Releasing lock...");
$this->pid = false;
}
$this->locked = false;
return true;
}
/**
* @return bool
* @throws Exception
*/
private function initialize()
{
if (!file_exists(self::LOCK_DIR))
{
if (!mkdir(self::LOCK_DIR))
{
throw new Exception(sprintf('Could not create folder LOCK_DIR (%s)', self::LOCK_DIR));
}
}
if (!is_writable(self::LOCK_DIR))
{
throw new Exception(sprintf('Unable to write to LOCK_DIR (%s)', self::LOCK_DIR));
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment