問題
佇列執行中, 未執行完成發生多次重試,佇列反覆執行
佇列執行中,突然掛起後卡在padding中,無法進入failed階段,程式碼執行結束無響應
問題發生
專案中遇到一個佇列,執行較久(執行某段指令碼大約10分鐘左右). 因為不想盯著任務執行,索性加上多次失敗重試. 將horizon
配置如下, 為了方便測試,我們把超時時間縮短
'long-task' => [
'connection' => 'redis',
'queue' => [QueueNameKeys::EXPORT_TASK],
'balance' => 'auto',
'memory' => 256,
'tries' => 5,
'timeout' => 10,
],
修改了tries=5
,timeout=10
隨即將測試程式碼加入測試執行
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class TestTask implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public function handle()
{
while (true) {
logger()->info('run in handle');
sleep(1);
}
}
public function failed(\Throwable $exception)
{
logger()->info('run in failed:' . $exception->getMessage());
}
}
將任務派發進入佇列,觀察執行結果
php artisan tinker
Psy Shell v0.11.4 (PHP 8.1.4 — cli) by Justin Hileman
>>> use App\Jobs\TestTask
>>> TestTask::dispatch()->onQueue('export-task')
=> Illuminate\Foundation\Bus\PendingDispatch {#5500}
這時候發現執行結果為 : 任務停留在Pending Jobs中, 但是日誌輸出停留在10條 , 等待很久都沒有進入重試機制
經過短暫的排查後, 發現 佇列超時配置受
redis
的retry_after
配置影響, 通俗來講就是,當retry_after
配置之後, 佇列的timeout
只負責中止程式的執行, 重試需要等待retry_after
. 部分小夥伴也會發現,自己的佇列有正常進入重試, 那正是因為retry_after
配置值較小. 達到配置超時後, 佇列正常進入重試 .
對這幾項配置,我們可以透過下面文章理解佇列的retry_after
,timeout
,backoff
到這裡問題似乎已經解決到這裡問題似乎已經解決
貌似只需要調整 retry_after
我們就可以完美進入重試
但是這裡看著以前的配置 retry_after = 90000
陷入沉思. 原來舊業務中有用到佇列 基於時間的嘗試 , 當時遇到佇列反覆重啟的問題 (達到retry_after
時間佇列任未消費完畢, 系統會自動重新啟動一個此佇列, 會造成佇列重複執行, 所以官方給的推薦是 retry_after
配置應該等於 佇列中最大的 timeout
值.) 而我當前的佇列就是需要執行特別久 . 這個導致了兩個問題
- 如果
retry_after
配的小, 我的長任務會被達到超時時間反覆執行 - 如果
retry_after
配的大, 我的短任務會在需要重試的時候, 等待這個配置時間結束,才能重試
如何解決這個問題
- 靈活配置
retry_after
?
檢視程式碼
發現這個配置只在
redis
連結的時候可以配置
為什麼這個配置不可以單獨修改,已經有了timeout
為什麼我還需要retry_after
, 這些問題這裡暫不在這裡討論
- 給佇列配置不同的
redis
連線 - 手動控制重試
1.給不同佇列配置不同redis
/config/queue.php
'connections' => [
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
'after_commit' => false,
],
'redis-horizon-10m' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 600,
'block_for' => null,
'after_commit' => false,
],
],
/config/horizon.php
'long-task' => [
'connection' => 'redis-horizon-10m',
'queue' => [QueueNameKeys::EXPORT_TASK],
'balance' => 'auto',
'memory' => 256,
'tries' => 3,
'timeout' => 10,
],
2.所有佇列不配置重試次數, 再failed
方法中定義自己的重試規則
3.您的其他騷操作(謝謝分享)
本作品採用《CC 協議》,轉載必須註明作者和本文連結