Laravel中用Redis來做任務隊列

利用Redis可以很方便的實現一個任務隊列,但是在Laravel中,Redis的隊列總會出現一個任務多次執行的問題。究其原因是它寫死了reserved的時長,也就是如果1分鐘後任務沒有執行完成,那麼這個任務就會被重新放回隊列。下面是隊列的簡單使用和執行原理。

設置

設置隊列使用Redis非常容易,在app/config/queue.php中配置


 
  1. ...

  2. 'default' => 'redis',

  3. ...

  4. 'connections' => array(

  5. ...

  6. 'redis' => array(

  7. 'driver' => 'redis',

  8. 'queue' => 'waa',

  9. ),

  10. ),

即可。

使用

使用時不需要多配置,只要寫好Queue類和其fire方法,在需要的位置出隊即可。具體方法可以看這裏


 
  1. class SendEmail {

  2.  
  3. public function fire($job, $data)

  4. {

  5. //

  6. $job->delete();

  7. }

  8.  
  9. }

  10.  
  11. Queue::push('SendEmail@send', array('message' => $message));

流程

Laravel利用artisan命令來執行出隊操作,然後進行任務的執行。方法調用如下:

  1. artisan queue:work
  2. WorkerCommand:fire()
  3. Worker:pop()
  4. Worker:getNextJob()
  5. RedisQueue:pop()
  6. Worker:process()

我遇到的問題就在這裏,在RedisQueue:pop()方法中,有這樣一句:

$this->redis->zadd($queue.':reserved', $this->getTime() + 60, $job);

這裏將當前執行的任務放到另外一個reserved隊列中,超時時間是60s。也就是說,如果60s後這個任務沒有被刪除掉,則任務會重新被放入隊列中來。因此,在實際的使用過程中,任務很可能被多次執行。解決的辦法是


 
  1. class SendEmail {

  2.  
  3. public function fire($job, $data)

  4. {

  5. $job->delete();

  6. // job

  7. }

  8.  
  9. }

即先刪除這個任務,再開始執行任務。

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