您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān) Laravel 中重復(fù)執(zhí)行同一個隊(duì)列任務(wù)的原因是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
源代碼文件:vendor/laravel/framework/src/Illuminate/Queue/RedisQueue.php
/** * The expiration time of a job. * * @var int|null */ protected $expire = 60;
這個 $expire 成員變量是一個固定的值,Laravel 認(rèn)為一個隊(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í)行超時等都會放入另外的集合保存起來,以便重試,過程如下:
1.把因執(zhí)行失敗的隊(duì)列從 delayed 集合重新 rpush 到當(dāng)前執(zhí)行的隊(duì)列中。
2.把因執(zhí)行超時的隊(duì)列從 reserved 集合重新 rpush 到當(dāng)前執(zhí)行的隊(duì)列中。
3.然后才是從隊(duì)列中取任務(wù)開始執(zhí)行,同時把隊(duì)列放入 reserved 的有序集合。
這里使用了 eval 命令執(zhí)行這個過程,用到了幾個 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ì)列的時候,同時會放一份到一個有序集合中,并使用過期時間戳作為分值。
只有當(dāng)這個任務(wù)完成后,再把有序集合中這個任務(wù)移除。從這個有序集合移除隊(duì)列的代碼就省略,我們看一下 Laravel 如何處理執(zhí)行時間大于 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 找出分值從無限小到當(dāng)前時間戳的元素,也就是 60 秒之前加入到集合的任務(wù),然后通過 zremrangebyrank 從集合移除這些元素并 rpush 到隊(duì)列中。
看到這里應(yīng)該就恍然大悟了。
如果一個隊(duì)列 60 秒沒執(zhí)行完,那么進(jìn)程在取隊(duì)列的時候從 reserved 集合中把這些任務(wù)又重新 rpush 到隊(duì)列中。
關(guān)于 Laravel 中重復(fù)執(zhí)行同一個隊(duì)列任務(wù)的原因是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。