欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

源碼分析 Laravel 重復(fù)執(zhí)行同一個(gè)隊(duì)列任務(wù)的原因

 更新時(shí)間:2017年12月25日 09:30:21   作者:豚 豚  
laravel 的隊(duì)列服務(wù)對(duì)各種不同的后臺(tái)隊(duì)列服務(wù)提供了統(tǒng)一的 API,下面這篇文章通過(guò)源碼分析給大家介紹了關(guān)于 Laravel 重復(fù)執(zhí)行同一個(gè)隊(duì)列任務(wù)的原因,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。

前言

laravel 的隊(duì)列服務(wù)對(duì)各種不同的后臺(tái)隊(duì)列服務(wù)提供了統(tǒng)一的 API。隊(duì)列允許你延遲執(zhí)行消耗時(shí)間的任務(wù),比如發(fā)送一封郵件。這樣可以有效的降低請(qǐng)求響應(yīng)的時(shí)間。

發(fā)現(xiàn)問題

在 Laravel 中使用 Redis 處理隊(duì)列任務(wù),框架提供的功能非常強(qiáng)大,但是最近遇到一個(gè)問題,就是發(fā)現(xiàn)一個(gè)任務(wù)被多次執(zhí)行,這是為什么呢?

先說(shuō)原因:

因?yàn)樵?Laravel 中如果一個(gè)隊(duì)列(任務(wù))執(zhí)行時(shí)間大于 60 秒,就會(huì)被認(rèn)為執(zhí)行失敗并重新加入隊(duì)列中,這樣就會(huì)導(dǎo)致重復(fù)執(zhí)行同一個(gè)任務(wù)。

這個(gè)任務(wù)的邏輯就是給用戶推送內(nèi)容,需要根據(jù)隊(duì)列內(nèi)容取出用戶并遍歷,通過(guò)請(qǐng)求后端 HTTP 接口發(fā)送。比如有 10000 個(gè)用戶,在用戶數(shù)量多或接口處理速度沒那么快的情況下,執(zhí)行時(shí)間肯定會(huì)大于 60 秒,于是這個(gè)任務(wù)就被重新加入隊(duì)列。情況更糟糕一點(diǎn),前面的任務(wù)如果都沒有在 60 秒執(zhí)行完,就都會(huì)重新加入隊(duì)列,這樣同一個(gè)任務(wù)就不止重復(fù)執(zhí)行一次了,而是多次。

下面從 Laravel 源代碼找一下罪魁禍?zhǔn)住?/strong>

源代碼文件:vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php

/**
 * The expiration time of a job.
 *
 * @var int|null
 */
protected $expire = 60;

這個(gè) $expire 成員變量是一個(gè)固定的值,Laravel 認(rèn)為一個(gè)隊(duì)列再怎么 60 秒也該執(zhí)行完了吧。取隊(duì)列方法:

public function pop($queue = null)
{
 $original = $queue ?: $this->default; 
 $queue = $this->getQueue($queue); 
 $this->migrateExpiredJobs($queue.':delayed', $queue); 
 if (! is_null($this->expire)) {
  $this->migrateExpiredJobs($queue.':reserved', $queue);
 } 
 list($job, $reserved) = $this->getConnection()->eval(
  LuaScripts::pop(), 2, $queue, $queue.':reserved', $this->getTime() + $this->expire
 ); 
 if ($reserved) {
  return new RedisJob($this->container, $this, $job, $reserved, $original);
 }
}

取隊(duì)列有幾步操作,因?yàn)殛?duì)列執(zhí)行失敗,或執(zhí)行超時(shí)等都會(huì)放入另外的集合保存起來(lái),以便重試,過(guò)程如下:

    1.把因執(zhí)行失敗的隊(duì)列從 delayed 集合重新 rpush 到當(dāng)前執(zhí)行的隊(duì)列中。

    2.把因執(zhí)行超時(shí)的隊(duì)列從 reserved 集合重新 rpush 到當(dāng)前執(zhí)行的隊(duì)列中。

    3.然后才是從隊(duì)列中取任務(wù)開始執(zhí)行,同時(shí)把隊(duì)列放入 reserved 的有序集合。

這里使用了 eval 命令執(zhí)行這個(gè)過(guò)程,用到了幾個(gè) lua 腳本。

從要執(zhí)行的隊(duì)列中取任務(wù):

local job = redis.call('lpop', KEYS[1])
local reserved = false
if(job ~= false) then
 reserved = cjson.decode(job)
 reserved['attempts'] = reserved['attempts'] + 1
 reserved = cjson.encode(reserved)
 redis.call('zadd', KEYS[2], ARGV[1], reserved)
end
return {job, reserved}

可以看到 Laravel 在取 Redis 要執(zhí)行的隊(duì)列的時(shí)候,同時(shí)會(huì)放一份到一個(gè)有序集合中,并使用過(guò)期時(shí)間戳作為分值。

只有當(dāng)這個(gè)任務(wù)完成后,再把有序集合中這個(gè)任務(wù)移除。從這個(gè)有序集合移除隊(duì)列的代碼就省略,我們看一下 Laravel 如何處理執(zhí)行時(shí)間大于 60 秒的隊(duì)列。

也就是這段 lua 腳本執(zhí)行的操作:

local val = redis.call('zrangebyscore', KEYS[1], '-inf', ARGV[1])
if(next(val) ~= nil) then
 redis.call('zremrangebyrank', KEYS[1], 0, #val - 1)
 for i = 1, #val, 100 do
  redis.call('rpush', KEYS[2], unpack(val, i, math.min(i+99, #val)))
 end
end
return true

這里 zrangebyscore 找出分值從無(wú)限小到當(dāng)前時(shí)間戳的元素,也就是 60 秒之前加入到集合的任務(wù),然后通過(guò) zremrangebyrank 從集合移除這些元素并 rpush 到隊(duì)列中。

看到這里應(yīng)該就恍然大悟了。

如果一個(gè)隊(duì)列 60 秒沒執(zhí)行完,那么進(jìn)程在取隊(duì)列的時(shí)候從 reserved 集合中把這些任務(wù)又重新 rpush 到隊(duì)列中。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Joomla語(yǔ)言翻譯類Jtext用法分析

    Joomla語(yǔ)言翻譯類Jtext用法分析

    這篇文章主要介紹了Joomla語(yǔ)言翻譯類Jtext用法,結(jié)合實(shí)例分析了語(yǔ)言翻譯類Jtext的基本原理與使用方法,需要的朋友可以參考下
    2016-05-05
  • 基于PHP的登錄和注冊(cè)的功能的實(shí)現(xiàn)

    基于PHP的登錄和注冊(cè)的功能的實(shí)現(xiàn)

    這篇文章主要介紹了基于PHP的登錄和注冊(cè)的功能的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 關(guān)于 Laravel Redis 多個(gè)進(jìn)程同時(shí)取隊(duì)列問題詳解

    關(guān)于 Laravel Redis 多個(gè)進(jìn)程同時(shí)取隊(duì)列問題詳解

    這篇文章主要給大家介紹了關(guān)于 Laravel Redis 多個(gè)進(jìn)程同時(shí)取隊(duì)列問題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • PHP中ajax無(wú)刷新上傳圖片與圖片下載功能

    PHP中ajax無(wú)刷新上傳圖片與圖片下載功能

    本文給大家分享php ajax無(wú)刷新上傳圖片與圖片下載功能的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下
    2017-02-02
  • laravel 解決ajax異步提交數(shù)據(jù),并還回填充表格的問題

    laravel 解決ajax異步提交數(shù)據(jù),并還回填充表格的問題

    今天小編就為大家分享一篇laravel 解決ajax異步提交數(shù)據(jù),并還回填充表格的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-10-10
  • php 模擬 asp.net webFrom 按鈕提交事件實(shí)例

    php 模擬 asp.net webFrom 按鈕提交事件實(shí)例

    需要php方面的項(xiàng)目開發(fā),php剛剛?cè)腴T,在寫按鈕提交過(guò)程中,asp.net里的按鈕事件更好些,下面有個(gè)實(shí)例,大家可以看看
    2014-10-10
  • PHP 中提示undefined index如何解決(多種方法)

    PHP 中提示undefined index如何解決(多種方法)

    這篇文章主要介紹了PHP 中提示undefined index如何解決(多種方法)的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • CodeIgniter框架基本增刪改查操作示例

    CodeIgniter框架基本增刪改查操作示例

    這篇文章主要介紹了CodeIgniter框架基本增刪改查操作,結(jié)合具體實(shí)例形式分析了CodeIgniter框架針對(duì)數(shù)據(jù)庫(kù)進(jìn)行創(chuàng)建、增刪改查等操作的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-03-03
  • PHP基于自增數(shù)據(jù)如何生成不重復(fù)的隨機(jī)數(shù)示例

    PHP基于自增數(shù)據(jù)如何生成不重復(fù)的隨機(jī)數(shù)示例

    這篇文章主要給大家介紹了利用PHP基于自增數(shù)據(jù)如何能生成不重復(fù)的隨機(jī)數(shù),文中給出了詳細(xì)的示例代碼供大家參考學(xué)習(xí),對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-05-05
  • PHP將敏感文字內(nèi)容替換為星號(hào)的操作方法

    PHP將敏感文字內(nèi)容替換為星號(hào)的操作方法

    在PHP中,將敏感文字用星號(hào)替換通常涉及到字符串的搜索和替換操作,下面是一個(gè)基本的示例,展示如何將特定的敏感詞替換為星號(hào),感興趣的朋友跟隨小編一起看看吧
    2024-04-04

最新評(píng)論