redis實現隊列任務

/**

  • 任務隊列
  • */
    class RedisQueue {
    private $_redis;

    public function __construct($param = null) {
    $this->_redis = RedisFactory::get($param);
    }

    /**

    • 入隊一個 Task
    • @param [type] $name 隊列名稱
    • @param [type] $id 任務id(或者其數組)
    • @param integer $timeout 入隊超時時間(秒)
    • @param integer $afterInterval [description]
    • @return [type] [description]
      */
      public function enqueue($name, $id, $timeout = 10, $afterInterval = 0) {
      //合法性檢測
      if (empty($name) || empty($id) || $timeout <= 0) return false;

      //加鎖
      if (!$this->_redis->lock->lock("Queue:{$name}", $timeout)) {
      Logger::get('queue')->error("enqueue faild becouse of lock failure: name = $name, id = $id");
      return false;
      }

      //入隊時以當前時間戳作爲 score
      $score = microtime(true) + $afterInterval;
      //入隊
      foreach ((array)$id as $item) {
      //先判斷下是否已經存在該id了
      if (false === $this->_redis->zset->getScore("Queue:$name", $item)) {
      $this->_redis->zset->add("Queue:$name", $score, $item);
      }
      }

      //解鎖
      $this->_redis->lock->unlock("Queue:$name");

      return true;

    }

    /**

    • 出隊一個Task,需要指定$id 和 $score
      • 如果$score 與隊列中的匹配則出隊,否則認爲該Task已被重新入隊過,當前操作按失敗處理
      • @param [type] $name 隊列名稱
      • @param [type] $id 任務標識
      • @param [type] $score 任務對應score,從隊列中獲取任務時會返回一個score,只有$score和隊列中的值匹配時Task纔會被出隊
      • @param integer $timeout 超時時間(秒)
      • @return [type] Task是否成功,返回false可能是redis操作失敗,也有可能是$score與隊列中的值不匹配(這表示該Task自從獲取到本地之後被其他線程入隊過)
        */
        public function dequeue($name, $id, $score, $timeout = 10) {
        //合法性檢測
        if (empty($name) || empty($id) || empty($score)) return false;

        //加鎖
        if (!$this->_redis->lock->lock("Queue:$name", $timeout)) {
        Logger:get('queue')->error("dequeue faild becouse of lock lailure:name=$name, id = $id");
        return false;
        }

        //出隊
        //先取出redis的score
        $serverScore = $this->_redis->zset->getScore("Queue:$name", $id);
        $result = false;
        //先判斷傳進來的score和redis的score是否是一樣
        if ($serverScore == $score) {
        //刪掉該$id
        $result = (float)$this->_redis->zset->delete("Queue:$name", $id);
        if ($result == false) {
        Logger::get('queue')->error("dequeue faild because of redis delete failure: name =$name, id = $id");
        }
        }
        //解鎖
        $this->_redis->lock->unlock("Queue:$name");

        return $result;
        }

      /**

      • 獲取隊列頂部若干個Task 並將其出隊
      • @param [type] $name 隊列名稱
      • @param integer $count 數量
    • @param integer $timeout 超時時間

      • @return [type] 返回數組[0=>['id'=> , 'score'=> ], 1=>['id'=> , 'score'=> ], 2=>['id'=> , 'score'=> ]]
        */
        public function pop($name, $count = 1, $timeout = 10) {
        //合法性檢測
        if (empty($name) || $count <= 0) return [];

        //加鎖
        if (!$this->_redis->lock->lock("Queue:$name")) {
        Logger::get('queue')->error("pop faild because of pop failure: name = $name, count = $count");
        return false;
        }

        //取出若干的Task
        $result = [];
        $array = $this->_redis->zset->getByScore("Queue:$name", false, microtime(true), true, false, [0, $count]);

      //將其放在$result數組裏 並 刪除掉redis對應的id
      foreach ($array as $id => $score) {
      $result[] = ['id'=>$id, 'score'=>$score];
      $this->_redis->zset->delete("Queue:$name", $id);
      }

      //解鎖
      $this->_redis->lock->unlock("Queue:$name");

      return $count == 1 ? (empty($result) ? false : $result[0]) : $result;
      }

      /**

      • 獲取隊列頂部的若干個Task
      • @param [type] $name 隊列名稱
    • @param integer $count 數量
    • @return [type] 返回數組[0=>['id'=> , 'score'=> ], 1=>['id'=> , 'score'=> ], 2=>['id'=> , 'score'=> ]]
      */
      public function top($name, $count = 1) {
      //合法性檢測
      if (empty($name) || $count < 1) return [];

      //取錯若干個Task
      $result = [];
      $array = $this->_redis->zset->getByScore("Queue:$name", false, microtime(true), true, false, [0, $count]);

      //將Task存放在數組裏
      foreach ($array as $id => $score) {
      $result[] = ['id'=>$id, 'score'=>$score];
      }

      //返回數組
      return $count == 1 ? (empty($result) ? false : $result[0]) : $result;
      }
      }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章