0

稍微解释一下,我有一个 Symfony2 设置。我正在使用我扩展的抽象命令类。我希望这些批次中的任何一个只能运行一次。我的目标是制作一个我打开并聚集的锁定文件,以便当 php 脚本以任何可能的方式终止时自动释放锁定。

为了实现这一点,我创建了一个名为 Lock 的类。此类扩展了 SplFileObject 并且基本上是在某处(通常是 /var/lock/*)创建 *.lock 的包装器。现在我在检测这个锁时遇到了问题。我确实有一个使用 fopen 和flock 的设置。由于某种原因,它不会再检测到它了。

我创建了一个 OOP 结构来基本上做我想做的事:

  • 确定锁定文件的名称(使用文件夹)
  • 创建一个锁对象
    • 如果目录不存在,则创建目录并锁定文件
    • 调用 SplFileObject::__construct()
  • 锁定文件

我不能让它与句柄和 spl 文件对象一起使用。如果我运行脚本,让它休眠 15 秒并在另一个控制台中运行相同的脚本,我将得到脚本成功锁定文件的结果,flock 返回 true。如果我在同一个脚本中的同一个锁文件上创建 2 个 Lock 对象,我在第一个锁上得到 true,在第二个上得到 false,这意味着它第二次无法获得锁。该脚本似乎有效。

但是,当我在两个脚本中使用 2 个锁运行脚本 2 次时,我在两个脚本上都得到 True 和 false ......这意味着它似乎没有跨脚本正确锁定文件:/

有没有人可以告诉我我做错了什么?我检查了文件名,两次运行脚本时它都相同。我尝试了多种权限,例如 777、755、733,但没有区别。

我这样称呼它(只是课程的一部分):

abstract class AbstractTripolisCommand extends ContainerAwareCommand
{
[...]
  /**
   * Locks the current file based on environments
   *
   * @param string $application_env
   * @param string $symfony_env
   */
  private function lockCommand($application_env, $symfony_env)
  {
    $lock_name  = "tripolis/$application_env/$symfony_env/" . crc32(get_class($this));
    $lock = new Lock($lock_name, 'w+', $this->getContainer()->get('filesystem'));
    var_dump($lock->lock());
    $lock2 = new Lock($lock_name, 'w+', $this->getContainer()->get('filesystem'));
    var_dump($lock2->lock());
    // results when ran 2 times at the same time
    // bool(true)
    // bool(false)
    // when I run this script twice I expect the second run at the same time
    // bool(false)
    // bool(false)

    if(!$lock->lock()) {
      throw new Tripolis\Exception('Unable to obtain lock, script is already running');
    }
  }
[...]
}

锁.php

namespace Something\Component\File;

use Symfony\Component\Filesystem\Filesystem;

/**
 * Creates a new SplFileObject with access to lock and release locks
 * Upon creation it will create the lock file if not exists
 *
 * The lock works by keeping a stream open to the lock file instead
 * of creating/deleting the lock file. This way the lock is always
 * released when the script ends or crashes.
 *
 * create a file named /var/lock/something/something.lock
 * <example>
 *   $lock = new Lock('something');
 *   $lock->lock();
 *   $lock->release();
 * </example>
 *
 * create a file named /var/lock/something/my-lock-file.lock
 * <example>
 *   $lock = new Lock('something/my-lock-file');
 *   $lock->lock();
 * </example>
 *
 * NOTE: locks that are not released are released
 * automatically when the php script ends
 *
 * @author Iltar van der Berg <ivanderberg@something.nl>
 */
class Lock extends \SplFileObject implements Lockable
{
  /**
   * @param string     $file_name
   * @param string     $open_mode
   * @param Filesystem $filesystem
   * @param string     $lock_directory
   */
  public function __construct($file_name, $open_mode = 'r+', Filesystem $filesystem = null, $lock_directory = '/var/lock')
  {
    $filesystem = $filesystem ?: new Filesystem();
    $file = self::touchLockFile($file_name, $lock_directory, $filesystem);
    parent::__construct($file, $open_mode);

  }

  /**
   * Returns true if the lock is placed, false if unable to
   *
   * @return boolean
   */
  public function lock()
  {
    return $this->flock(LOCK_EX | LOCK_NB);
  }

  /**
   * Returns true if the lock is released
   *
   * @return bool
   */
  public function release()
  {
    return $this->flock(LOCK_UN);
  }

  /**
   * Attempts to create a lock file for a given filename and directory
   * it will return a string if the file is touched
   *
   * @param  string     $file_name
   * @param  string     $lock_directory
   * @param  Filesystem $filesystem
   * @return string
   */
  private static function touchLockFile($file_name, $lock_directory, Filesystem $filesystem)
  {
    $lock_file_path = explode('/', $file_name);
    $lock_file      = array_pop($lock_file_path);

    $path = "$lock_directory/" . (empty($lock_file_path)
      ? $lock_file
      :  implode('/', $lock_file_path));

    $lock_file = "$path/$lock_file.lock";

    if(!$filesystem->exists($path) || !is_dir($path)) {
      $filesystem->mkdir($path);
    }

    return $lock_file;
  }
}
?>
4

1 回答 1

1

我敢打赌,锁或文件比您想象的更早被销毁,因为拥有这些对象的函数返回,从而使对象有资格进行垃圾回收。

于 2012-12-21T16:08:42.657 回答