۶ تلهٔ Queue لاراول
خلاصهٔ کاملتر
نویسنده پست، Oussama Mater، شش تا از اشتباههایی که تو سالها کار با صفهای لاراول کرده رو جمع کرده. اولیش retryUntil() هست، یعنی متدی که میگه تا چه لحظهای تلاش برای اجرای جاب ادامه داشته باشه. به گفتهٔ نویسنده خیلیها فکر میکنن این مهلت از لحظهٔ شروع پردازش حساب میشه، ولی retryUntil() همون موقع که جاب روی صف push میشه ارزیابی و تایماستمپش داخل payload ذخیره میشه.
نتیجهش اینه که یه جاب یادآور با تأخیر یکروزه، وقتی به worker میرسه تاریخ انقضاش گذشته و فقط MaxAttemptsExceededException میگیره؛ handle() هیچوقت اجرا نمیشه. تلهٔ بعدی هم از جنس همین پیشفرضهاست: با queue:work اگه $tries رو ننویسی جاب یک بار تلاش میشه، ولی پیشفرض Horizon صفره و صفر یعنی بینهایت. یعنی همون جاب روی production بیوقفه retry میشه و Sentry رو پر میکنه.
تلهٔ سوم سر جابهای unique و قفلشونه. با ShouldBeUniqueUntilProcessing قفل به محض شروع پردازش آزاد میشه، پس اگه جاب چند ساعت تو صف بمونه و موقع برداشتن بهخاطر retryUntil() فیل بشه، مسیر failure فرض میکنه قفل آزاد شده و بهش دست نمیزنه. قفل سر جاش میمونه و از اون به بعد هر dispatch بیصدا رد میشه. نویسنده میگه زمان انقضای این قفل تو سه درایور Database و Redis و File سه جواب مختلف داره، و همهشون عملاً بینهایتن، پس uniqueFor رو صریح بذار.
مورد چهارم retry_after هست که پیشفرضش ۹۰ ثانیهست: اگه از timeout جاب کمتر باشه، worker دوم همون جاب رو برمیداره و خطای «attempted too many times» میده درحالیکه worker اول داره موفق تمومش میکنه. پس retry_after همیشه باید بزرگتر از timeout باشه.
دو تای آخر هم rate limiter لاراوله که پنجرهٔ ثابت داره و سر مرز دو پنجره میتونه ۱۹ درخواست رو تو یک دقیقه عبور بده و خطای ۴۲۹ بگیری، و SerializesModels که فقط کلاس و id و اسم رابطهها رو ذخیره میکنه، پس worker رابطهها رو بدون شرطهای قبلی دوباره لود میکنه.
درسی که نویسنده از همهشون میگیره اینه که با جابها صریح باش. پیشفرضها بد نیستن، ولی خوندن یه $timeout نوشتهشده خیلی بهتر از حدسزدنشه، و صریح بودن یعنی وقتی چیزی خراب شد لازم نیست حدس بزنی چی شده.
نکات کلیدی:
- retryUntil() هنگام push ارزیابی میشه، نه هنگام پردازش
- پیشفرض tries تو Horizon صفر یعنی بینهایته، تو queue:work یک بار
- با ShouldBeUniqueUntilProcessing قفلِ جابی که قبل از پردازش فیل بشه آزاد نمیشه؛ uniqueFor رو صریح بذار
- retry_after پیشفرض ۹۰ ثانیهست و باید بزرگتر از timeout جاب باشه
- rate limiter لاراول پنجرهٔ ثابت داره، پس سر مرز دو پنجره ۲ برابر سهمیه عبور میکنه
- SerializesModels شرطهای رابطه رو ذخیره نمیکنه؛ با #[WithoutRelations] جداشون کن




