- Laravel ponúka jednotné API pre fronty s viacerými ovládačmi (databáza, Redis, SQS…) a oddelením pripojení a logických frontov.
- Úlohy umožňujú presunúť náročné úlohy na pozadie s podporou serializácie modelov, middlewaru, jednorazových úloh, šifrovania, dávok a reťazcov.
- Pracovníci sú spravovaní pomocou queue:work, Supervisor a príkazov ako queue:pause/queue:continue, ktoré riadia opakované pokusy, časové limity a priority.
- Existuje kompletný ekosystém pre zlyhania, monitorovanie a testovanie (failed_jobs, queue:retry, queue:monitor, Queue::fake), vďaka ktorému sú fronty v produkčnom prostredí spoľahlivé.
Práca s frontami v Laraveli je takmer nevyhnutná v každom serióznom projekte: odosielanie e-mailov, spracovanie súborov CSV, generovanie PDF, zmena veľkosti obrázkov, volanie externých API… Ak sa toto všetko robí v hlavnej HTTP požiadavke, webová stránka sa spomalí, zobrazí sa 500 chýb a používateľ nakoniec zúfalo hľadí na prázdnu obrazovku.
Dobrou správou je, že Laravel ponúka výkonnú a flexibilnú infraštruktúru pre radenie , ktorá vám umožňuje delegovať ťažkú prácu na procesy na pozadí, spravovať ich podľa priority, zoskupovať ich do dávok, monitorovať ich, opakovať ich v prípade zlyhania a dokonca dočasne pozastaviť procesy kvôli údržbe. Pozrime sa bližšie (a nič nevynecháme) na to, ako z toho vyťažiť maximum, vrátane toho, ako pozastaviť, obnoviť a ovládať jeho správanie v produkčnom prostredí.
Základné pojmy: pripojenia, fronty a ovládače
V Laraveli, predtým ako čokoľvek pozastavíte, musíte pochopiť rozdiel medzi pripojenia frontov a samotné fronty. V config/queue.php máš pole connections kde definujete každý backend: databáza, redis, beanstalkd, sqs, synchronizácia, null, záložné prepnutie, rabbitmq (ak ho pridáte) atď.
Každé pripojenie môže mať niekoľko logické fronty (názvy ako default, emails, high, low, importsAtribút queue Každé pripojenie označuje, ktorý je predvolený front, kam sa úlohy umiestnia, ak nie je zadaný iný. onQueue()Takto môžete robiť veci ako:
- Rýchly rad pre e-maily alebo krátke transakcie.
- Ďalšia nízka priorita pre dlhé úlohy, ako je spracovanie videí alebo rozsiahlych správ.
- Fronty segmentované podľa typu úlohy:
imports,notificaciones,reportes, Atď
Keď spustíte pracovníka s php artisan queue:workPredvolene počúva front zadaný ako predvolené na vybranom pripojení. Ak chcete uprednostniť, môžete zadať viacero frontov oddelených čiarkami:
php artisan queue:work redis --queue=high,default,low
Týmto spôsobom pracovník najprv spracuje high , potom default a až potom low , čo je kľúčové, keď je systém zaťažený a nechcete, aby 30-minútová správa blokovala e-maily s vysokou prioritou.
Ovládače frontov a predpoklady
Laravel ponúka jednotné API pre niekoľko ovládačov frontu , ale každý má svoje vlastné špecifické funkcie a závislosti. Výber správneho ovládača je kľúčový pred diskusiou o pozastavení workerov.
Databáza vodičov
Vodič databázy Ukladá úlohy do SQL tabuľky (zvyčajne jobsJeho nastavenie je jednoduché a je ideálny pre malé projekty alebo vývojové prostredia, kde sa nechcete hrať s Redisom alebo SQS.
Základné kroky:
- Vygenerujte migráciu:
php artisan queue:table(alebo v novších verziách sa dodáva akocreate_jobs_tablepredvolené). - Spustiť migrácie:
php artisan migrate. - konfigurácia QUEUE_CONNECTION=databáza v
.enva potvrďte vconfig/queue.phpže'default' => env('QUEUE_CONNECTION','database').
Je to pohodlné a dostatočne robustné, ale s mnohými radmi a veľkou prevádzkou sa to môže stať úzkym hrdlom , pretože všetko prechádza cez tú istú relačnú databázu.
Ovládač Redis
Ovládač Redis je štandardným pracantom v produkčnom prostredí. Je rýchly, podporuje pokročilé funkcie (zamykanie, obmedzovanie rýchlosti, atomické zámky, Horizon atď.) a veľmi dobre sa škáluje.
Dôležité body:
- Musíte nakonfigurovať pripojenie Redis v
config/database.php. - Možnosti
serializerycompressionz Redisu Nie sú kompatibilné s vodičom frontu. - Ak používate Klaster RedisNázvy frontov musia mať hashtag, napríklad
{default}aby všetky kľúče v danom rade spadali do rovnakého slotu. - Možnosť
block_forUmožňuje pracovníkovi blokovať sa počas čakania na úlohy niekoľko sekúnd namiesto neustáleho dotazovania: šetrí CPU a redukuje dotazy na server Redis.
Napríklad:
'redis' => ,
Ak vložíte blok_pre = 0Pracovník zostáva zablokovaný na neurčito, kým sa neuvoľní práca, čo je potrebné mať na pamäti, ak chcete, aby rýchlo reagoval na signály ako SIGTERM alebo pozastaviť príkazy.
Ďalšie ovládače: SQS, Beanstalkd, null, failover…
Okrem databáz a redis podporuje Laravel aj iné systémy :
- Amazon SQSRady spravované spoločnosťou AWS s podporou pre FIFOSkupiny správ, deduplikácia a rozšírené nastavenia viditeľnosti. Vyžaduje sadu SDK.
aws/aws-sdk-php. - BeanstalkdVeľmi rýchle a jednoduché, pomocou balíka
pda/pheanstalk. - synchronizovať: vykonáva úlohy bezodkladne v tom istom procese. Užitočné pri vývoji alebo testovaní, ale v produkcii je to prakticky ako keby ste fronty vôbec nepoužívali.
- null: Zahodí úlohy hneď po ich „odoslaní“. Používa sa na úplné vypnutie systému radenia.
- failoverTo vám umožňuje nakonfigurovať viacero pripojení a ak to primárne zlyhá, Laravel sa pokúsi presunúť úlohu na ďalšie v zozname. Ideálne pre prostredia, kde vysoká dostupnosť je kritická.
Na úrovni pozastavovania a obnovovania workerov je logika prakticky rovnaká bez ohľadu na ovládač, pretože je riadená z príkazov Artisan a triedy Worker , nie z backendu frontu.
Vytváranie úloh a serializácia modelov
Un zamestnania V Laraveli je to jednoducho trieda, ktorá zapuzdruje úlohu, ktorá sa má vykonať vo fronte. Zvyčajne sa generuje pomocou Artisanu a ukladá sa do app/Jobs.
Postup vytvorenia:
php artisan make:job ProcessPodcast
Vygenerovaná trieda náradie ShouldQueue a zvyčajne používa vlastnosti Dispatchable, InteractsWithQueue, Queueable y SerializesModelsSrdce je v metóde handle()čo pracovník urobí, keď práca príde.
Obzvlášť silnou funkciou je automatická serializácia modelov Eloquentu . Ak v konštruktore úlohy prijmete model, Laravel nepridá do frontu celý objekt, iba jeho identifikátor. Po spracovaní úlohy rekonštruuje model z databázy s načítanými vzťahmi.
Typický príklad (v pseudokóde, aby sa predišlo doslovnému opakovaniu):
- Staviteľ dostane Podcast $podcast.
- Táto vlastnosť
SerializesModelsJe zodpovedný za uloženie ID. - En
handle(AudioProcessor $processor)Vy robíte ťažkú prácu (napríklad spracovanie zvuku).
Ak nechcete, aby boli vzťahy v modeli serializované (aby užitočné zaťaženie nebolo obrovské), môžete použiť $model->withoutRelations() alebo v PHP 8 atribút # na nehnuteľnosti propagovanej staviteľom.
Vkladanie závislostí do metódy handle
Ďalšou výhodou je, že môžete vložiť služby priamo do metódy handle (ako keby to bol kontrolér), pretože Laravel tiež používa kontajner služieb v úlohách. Napríklad môžete požiadať o AudioProcessorHTTP klienti, repozitáre atď. a framework sa postará o ich riešenie.
Ak potrebujete ultrajemnú kontrolu nad tým, čo sa nazýva handlemôžete použiť Container::bindMethod() u poskytovateľa služieb a definovať logiku vstrekovania sami, ale vo väčšine prípadov nie je potrebné veci až tak komplikovať.
Middleware úloh
Rovnako ako trasy majú middleware, aj úlohy môžu mať špecifický middleware ktoré sa spúšťajú pred a po úlohe. To výrazne znižuje počet opakujúcich sa kódov v metódach handle() a je obzvlášť užitočný pre:
- Obmedzenie rýchlosti s Redisom.
- vyhnúť sa sa prekrýva diel, ktoré sa dotýkajú toho istého zdroja.
- Pravidelné výnimky pre nestabilné API.
- Preskakovanie úloh za určitých podmienok (
Skipmiddleware).
Middleware sa zvyčajne umiestňuje do app/Jobs/Middleware a sú vrátené z metódy middleware() Z knihy Jób. Koncepčný príklad:
public function middleware(): array { return ;
Špeciálne typy úloh: jedinečné, šifrované a uzamknuté
Laravel vám umožňuje označiť určité úlohy ako jedinečný aby sa zabezpečilo, že žiadne dve identické inštancie nebudú nikdy zaradené do frontu súčasne. Toto sa dosiahne implementáciou rozhrania ShouldBeUnique o ShouldBeUniqueUntilProcessinga podporuje definovanie kľúča uniqueId() a čas uniqueFor.
Toto je ideálne na veci ako:
- Prepočítajte index vyhľadávania produktu: iba raz na produkt kým sa to neskončí.
- Synchronizácie s externými službami, ktoré neumožňujú súbežné požiadavky na ten istý zdroj.
V spodnej časti Laravel používa atómový zámok vyrovnávacej pamäte (Redis, memcached, databáza atď.). Ovládač vyrovnávacej pamäte pre daný zámok si môžete vybrať aj pomocou uniqueVia().
Okrem toho je tu rozhranie ShouldBeEncrypted, čím označíte, že úloha je kompletná Zadajte svoj kód pred vstupom do frontuVeľmi užitočné pri prenose citlivých údajov, keď nechcete, aby sa prenášali ako obyčajný text cez Redis, SQS alebo databázu.
Odosielanie, odkladanie a vykonávanie úloh v rôznych režimoch
Keď je vaša úloha definovaná, spustíte ju pomocou Job::dispatch() z ovládačov, poslucháčov udalostí, príkazov Artisan alebo dokonca uzávierok. Parametre, ktoré odovzdávate dispatch Idú priamo k staviteľovi Jóba.
Zaujímavé variácie:
dispatchIf()ydispatchUnless()upravovať zásielku v jednom riadku.delay()takže úloha nemôže byť spracovaná až do určitého dátumu/času.dispatchAfterResponse()oafterResponse()endispatch()Uzávierky, ktoré odkladajú vykonanie, kým sa neodošle odpoveď HTTP, ale v rámci toho istého PHP procesu.dispatchSync()spustiť úlohu synchrónne (bez prechodu cez front), ale s opätovným použitím tej istej triedy.- Špeciálne spojenia, ako napr.
deferredobackgroundvykonať po odpovedi, v tom istom procese alebo v novom PHP procese.
Nakoniec môžete zadať pripojenie a front pomocou reťazených metód onConnection() y onQueue(), či už pri odosielaní alebo v nástroji na tvorbu úloh.
Jemná kontrola: opakované pokusy, odloženie, časové limity a spracovanie chýb
Veľkou súčasťou práce s frontami v Laraveli je rozhodovanie o tom, koľkokrát sa má úloha opakovať , ako dlho sa má čakať medzi pokusmi a kedy sa má považovať za zlyhanie.
Dostupné možnosti:
--triesenqueue:worknastaviť maximálny počet pokusov pre všetky úlohy daného pracovníka (pokiaľ úloha nedefinuje svoj vlastný)$triesotries()).$triesalebo metódatries()v triede Job pre riadenie jednotlivých úloh.retryUntil()povedať: „Skúšaj to znova, koľko chceš, až doteraz, potom je to neúspech.“ Ak sa to zhoduje stries, príkazretryUntil.$maxExceptionsprerušiť, keď je problém spôsobený opakovanými neošetrenými výnimkami.$timeouto--timeoutna označenie, koľko sekúnd môže úloha bežať predtým, ako pracovník ukončí podradený proces.$failOnTimeoutoznačiť úlohu ako neúspešnú v prípade uplynutia časového limitu.$backoffmetódabackoff()definovať, ako dlho čakať medzi opakovanými pokusmi, a to aj pri exponenciálnych hodnotách.
Ak úloha vyvolá nezachytenú výnimku, Laravel... uvoľňuje sa späť do chvosta kým sa nevyčerpajú nakonfigurované pokusy. Toto môžete ovládať manuálne pomocou release($segundos) o fail($exception) keď chcete úlohu zámerne označiť ako neúspešnú.
Zlyhané úlohy, tabuľka failed_jobs a prerezávanie
Keď Jób vyčerpá svoje pokusy, začne sa o ňom uvažovať neúspešná práca a Laravel ho vloží do tabuľky failed_jobs (alebo v DynamoDB, ak to tak nakonfigurujete). Táto tabuľka uchováva UUID, pripojenie, front, dáta úlohy a vyvolanú výnimku.
Užitočné príkazy:
php artisan queue:failedvymenovať tie, ktoré zlyhali.php artisan queue:retry <id|all>aby som ich skúsil znova.php artisan queue:forget <id>vymazať jeden.php artisan queue:flushodstrániť všetky (s možnosťou hodín v novších verziách).php artisan queue:prune-failed --hours=48automaticky odstrániť staré záznamy.
V časti Úlohy môžete definovať metódu failed(Throwable $exception) Pre dodatočné čistenie: upozornenie používateľa, vrátenie čiastočných akcií, zapisovanie špecializovaných protokolov atď. Upozorňujeme, že na volanie sa vytvorí nová inštancia úlohy. failed()Preto sa nespoliehajte na zmeny majetku vykonané v handle().
Dávkovanie úloh: dávky úloh a ich kombinovanie pomocou reťazcov
Keď potrebujete spustiť stovky alebo tisíce súvisiacich úloh (napríklad importovať obrovský CSV súbor po častiach, spracovávať súbory v dávkach, čistiť dáta atď.), je vhodné použiť dávkovú funkcionalitu Laravelu .
Základný tok:
- vytvorte tabuľku
job_batchessphp artisan queue:batches-table && php artisan migrate. - Označte úlohy, ktoré budú súčasťou dávok, pomocou vlastnosti
Batchable. - použitie
Bus::batch()odoslať sadu úloh s spätnými volaniamithen,catchyfinally. - Prístup k dávke z každej úlohy pomocou
$this->batch()a skontrolujte, či je zrušený. - Možnosť pridať ďalšie úlohy do prebiehajúcej dávky s
$this->batch()->add().
Dávky sa krásne integrujú s reťazcami : reťazce môžete mať v rámci dávky alebo dávky ako prvky väčšieho reťazca. Toto je obzvlášť užitočné, keď chcete, aby viacero reťazcov bežalo „paralelne“ a spúšťalo niečo po ich dokončení.
Vykonávanie, priority a nasadenie pracovníkov
Všetko kúzlo radov sa deje, pretože máte jeden alebo viac pracovníkov spustenie príkazu queue:work (o queue:listen(hoci ten druhý je menej efektívny). Tieto procesy sú dlho bežiace démony, ktoré počúvajú svoje príslušné fronty.
Kľúčové možnosti queue:work:
- Spojenie:
php artisan queue:work redis,queue:work database, Atď - Fronty:
--queue=high,default,lowstanoviť si priority. - jedenásť: spracuje jednu úlohu a ukončí sa.
- –max-jobs: spracuje X úloh a ukončí sa (aby sa periodicky reštartovali workeri a uvoľnila pamäť).
- –maximálny čas: spracováva sa N sekúnd a potom sa ukončí.
- –spánok: sekundy čakania, keď nie sú k dispozícii žiadne úlohy.
- –zastaviť-keď-je-prázdno: vyprázdni front a čisto sa zatvorí (ideálne v prostrediach Docker alebo pri jednorazových úlohách).
- –časový limit: sekundy časového limitu na úlohu, ako sme už spomenuli.
- -force: na spracovanie úloh, aj keď je aplikácia v režime údržby.
Keďže tieto procesy bežia dlho, v produkčnom prostredí sa takmer vždy používa monitor procesov, ako napríklad Supervisor (v Linuxe), na spustenie X workerov, ich reštartovanie v prípade zlyhania a správu protokolov. Typický konfiguračný blok Supervisor pre Laravel definuje:
- povel s
php artisan queue:work ...betón. - numprocs aby sa určilo, koľko pracovníkov sa má spustiť paralelne.
- Cesty protokolov, používateľ, automatické reštarty atď.
Pozastavenie a obnovenie frontov v Laraveli
Poďme sa pozrieť na to, čo je pri údržbe často dôležité: ako pozastaviť procesy vo fronte bez ich náhleho zastavenia a bez toho, aby úlohy zostali nedokončené. Laravel ponúka niekoľko mechanizmov na ovládanie tohto procesu, niektoré novšie, niektoré klasické.
Pauza: front: signály pauzy a prerušenia
V novších verziách Laravel pridáva špecifické príkazy na pozastavenie a obnovenie vykonávania workerov:
php artisan queue:pause: povie systému, aby prestal prijímať nové úlohy, ale nechal dokončiť tie, ktoré už prebiehajú.php artisan queue:continue: obnoví spracovanie nových úloh od miesta, kde prestalo.
Tieto príkazy fungujú tak, že odosielajú signály pracovníkom prostredníctvom mechanizmu vyrovnávacej pamäte, ktorý Laravel používa interne. Preto je dôležité mať správne nakonfigurovaný ovládač vyrovnávacej pamäte (memcached, redis, database, file atď.), aj keď vaša skutočná fronta vyrovnávacej pamäte je niečo iné.
Dôležité: Pozastavenie frontu alebo pracovníka nezruší ani neodstráni úlohy, ktoré sú už zaradené do frontu ; iba zabráni odstráneniu ďalších úloh z frontu počas trvania pozastavenia.
Prieskum prerušení a ich vplyv na výkon
Vždy, keď worker dokončí úlohu, Laravel skontroluje vyrovnávaciu pamäť, či neobsahuje signály reštartu, pozastavenia alebo pokračovania . Toto má zanedbateľné náklady, ale existuje. Ak sa mimoriadne zameriavate na výkon a viete, že nebudete musieť pozastaviť alebo reštartovať workerov z príkazov, môžete toto dotazovanie vypnúť volaním:
Queue::withoutInterruptionPolling();
Alebo dokonca upraviť statické vlastnosti Illuminate\Queue\Worker zakázať konkrétne dotyky ($reštartovateľné, $pauzovateľnéAk to však urobíte a potom sa pokúsite použiť queue:pause o queue:restartrobotníci Nezistia toJe to dizajnérske rozhodnutie, ktoré by sa malo starostlivo zvážiť.
Manuálne pozastavenie pomocou Supervisora alebo Dockera
Okrem vlastných príkazov Laravelu sú v produkčných prostrediach procesy často nepriamo „pozastavené“:
- Zastavenie programu v Supervisore (
supervisorctl stop laravel-worker:*), čo zabíja alebo zastavuje pracovníkov. - použitím –zastaviť-keď-je-prázdno v nasadeniach, aby pracovníci dokončili to, čo je vo fronte, a potom sa vypli.
- V Dockeri, nechať kontajner spracovať s
--stop-when-emptya potom sa vypne.
Rozdiel s queue:pause Úplným zastavením procesov zastavíte spracovanie úloh, kým sa pracovníkov reštartuje. vnútorná pauza Procesy môžete uchovávať v pamäti a čakať na príkaz continueToto je užitočné pre rýchle vrátenie zmien alebo krátke obdobia údržby.
Databázové transakcie a after_commit
Klasická chyba: odosielanie úloh v rámci databázových transakcií . Ak si nedáte pozor, pracovník môže úlohu vykonať ešte pred vykonaním potvrdenia (commit) a model alebo údaje, ktoré očakávate, ešte nemusia byť v databáze.
Aby ste sa tomuto tancovaniu vyhli, máte dve možnosti:
- Aktivovať
'after_commit' => truev konfigurácii pripojenia frontu. Preto je každá úloha odoslaná v rámci transakcie interne odložená, kým nie je potvrdená. - Používajte metódy pre jednotlivé úlohy
afterCommit()obeforeCommit()pri odosielaní vynútiť správanie iba v konkrétnych úlohách.
Ak je transakcia obrátená, úlohy odoslané počas nej sa zahodia bez toho, aby sa dostali do frontu, čo je presne to, čo je zvyčajne žiaduce na zachovanie konzistencie.
Monitorovanie, čistenie frontu a testovanie
Keď už máte fronty naplno rozbehnuté, nestačí len zahodiť úlohy a zabudnúť na ne; mali by ste monitorovať a testovať, ako sa všetko správa.
Užitočné nástroje a príkazy:
queue:clearvyprázdniť konkrétny front (SQS, Redis, databáza).queue:monitormonitorovať počet úloh v určitých frontoch a spúšťať udalosťQueueBusyak prekročia určitú hranicu.- Pracovné udalosti ako
Queue::before,Queue::after,Queue::loopingyQueue::failingna pripojenie vlastnej logiky (logy, metriky, vrátenia zmien atď.). - Falzifikáty v testovaní použitie
Queue::fake()yBus::fake()overiť, či boli úlohy, reťazce alebo dávky odoslané bez ich skutočného vykonania.
V testoch môžete uviesť veci ako „táto úloha bola zaradená do frontu X-krát“ , „reťazec s týmito úlohami bol odoslaný v tomto poradí“ alebo „žiadna konkrétna úloha nebola zaradená do frontu“, čo poskytuje veľa bezpečnosti v zložitých tokoch.
S celým týmto ekosystémom – ovládačmi ako Redis alebo SQS, dobre navrhnutými úlohami, middlewareom na doladenie, dávkami, reťazcami, konfiguráciou opakovaných pokusov, pracovníkmi spravovanými supervízorom a príkazmi ako queue:pause y queue:continue— Laravel vám umožňuje zvládnuť spracovanie na pozadí s presnosťou na milimeter, od typického odosielania e-mailov až po architektúry distribuovaných frontov s prepínaním pri zlyhaní, čím sa zabezpečí, že vaša aplikácia bude naďalej rýchlo reagovať na vrstve HTTP, aj keď sa pod ňou vykonáva náročná práca bez blokovania používateľa.