Reputation: 2624
I need a way to prevent multiple run on a process on symfony 1.4.
Something like: when a user is running this process, the other user who tries to run this process will get a warning message inform that the process is running.
Is there a way to implement it without using database?
Upvotes: 0
Views: 909
Reputation: 8201
kirugan's method will probably work in most cases, but it's susceptible to race conditions and can get stuck in the event of a crash.
Here's a more robust solution. It uses PHP's file locking so you know the lock is atomic, and if you forget to release the lock later or your process crashes, it gets released automatically. By default, getting a lock is non-blocking (i.e. if the lock is already held by another process, getLock()
will instantly return FALSE). However, you can have the call block (i.e. wait until the lock becomes available) if you'd like. Finally, you can have different locks for different parts of your code. Just use a different name for the lock.
The only requirement is that the directory returned by getLockDir()
must be server-writable. Feel free to change the location of the lock dir.
Note: I think flock() may behave differently on Windows (I use linux), so double check that if its an issue for you.
myLock.class.php
class myLock
{
/**
* Creates a lockfile and acquires an exclusive lock on it.
*
* @param string $filename The name of the lockfile.
* @param boolean $blocking Block until lock becomes available (default: don't block, just fail)
* @return mixed Returns the lockfile, or FALSE if a lock could not be acquired.
*/
public static function getLock($name, $blocking = false)
{
$filename = static::getLockDir() . '/' . $name;
if (!preg_match('/\.lo?ck$/', $filename))
{
$filename .= '.lck';
}
if (!file_exists($filename))
{
file_put_contents($filename, '');
chmod($filename, 0777); // if the file cant be opened for writing later, getting the lock will fail
}
$lockFile = fopen($filename, 'w+');
if (!flock($lockFile, $blocking ? LOCK_EX : LOCK_EX|LOCK_NB))
{
fclose($lockFile);
return false;
}
return $lockFile;
}
/**
* Free a lock.
*
* @param resource $lockFile
*/
public static function freeLock($lockFile)
{
if ($lockFile)
{
flock($lockFile, LOCK_UN);
fclose($lockFile);
}
}
public static function getLockDir()
{
return sfConfig::get('sf_root_dir') . '/data/lock';
}
}
How to use
$lockFile = myLock::getLock('lock-name');
if ($lockFile) {
// you have a lock here, do whatever you want
myLock::freeLock($lockFile);
}
else {
// you could not get the lock. show a message or throw an exception or whatever
}
Upvotes: 3
Reputation: 2624
Here is my functions for this:
function lock(){
$file = __DIR__ . '/file.lock';
if(file_exists($file)){
/* exit or whatever you want */
die('ALREADY LOCKED');
}
touch($file);
}
function unlock(){
$file = __DIR__ . '/parser.lock';
if(file_exists($file)){
unlink($file);
}else{
echoln("unlock function: LOCK FILE NOT FOUND");
}
}
function exitHandler(){
echoln('exitHandler function: called');
unlock();
}
Use lock
function in the beginning, and set exitHandler
function in register_shutdown_function()
. You can save this snippets as class with the same methods or save it like helper file
Upvotes: 1