- Laravel nudi objedinjeni API za redove čekanja s više drajvera (baza podataka, Redis, SQS…) i razdvajanjem između konekcija i logičkih redova čekanja.
- Poslovi omogućavaju premještanje teških zadataka u pozadinu, uz podršku za serijalizaciju modela, middleware, jednokratne poslove, šifriranje, serije i stringove.
- Radnicima se upravlja pomoću queue:work, Supervisor i naredbi kao što su queue:pause/queue:continue, kontrolirajući ponovne pokušaje, vremenska ograničenja i prioritete.
- Postoji kompletan ekosistem za kvarove, praćenje i testiranje (failed_jobs, queue:retry, queue:monitor, Queue::fake) koji čini redove pouzdanim u produkciji.
Rad s redovima čekanja u Laravelu je gotovo obavezan u svakom ozbiljnom projektu: slanje e-pošte, obrada CSV datoteka, generiranje PDF-ova, promjena veličine slika, pozivanje vanjskih API-ja... Ako se sve to uradi u glavnom HTTP zahtjevu, web stranica postaje spora, pojavljuje se 500 grešaka, a korisnik na kraju očajnički zuri u prazan ekran.
Dobra vijest je da Laravel nudi moćnu i fleksibilnu infrastrukturu čekanja koja vam omogućava da delegirate teške zadatke pozadinskim procesima, upravljate njima po prioritetu, grupišete ih u grupe, pratite ih, ponovo pokušavate kada ne uspiju, pa čak i privremeno pauzirate radnike radi održavanja. Pogledajmo detaljno (i ništa ne izostavimo) kako izvući maksimum iz toga, uključujući kako pauzirati, nastaviti i kontrolirati njegovo ponašanje u produkciji.
Osnovni koncepti: veze, redovi čekanja i upravljački programi
U Laravelu, prije nego što bilo šta pauzirate, morate razumjeti razliku između veze redova čekanja i sami redovi čekanja. En config/queue.php imate niz connections gdje definirate svaki backend: baza podataka, redis, beanstalkd, sqs, sinhronizacija, null, prebacivanje na drugi sistem, rabbitmq (ako ga dodate), itd.
Svaka veza može imati nekoliko logički redovi (imena poput default, emails, high, low, importsAtribut queue Svaka veza označava koji je zadani red u koji će poslovi ići ako nije navedeno ništa drugo. onQueue()Na ovaj način možete uraditi stvari poput:
- Brzi red za e-poruke ili kratke transakcije.
- Još jedan nizak prioritet za duge zadatke poput obrade videa ili velikih izvještaja.
- Redovi segmentirani po vrsti zadatka:
imports,notificaciones,reportes, Itd
Kada pokrenete radnika sa php artisan queue:workPodrazumevano, osluškuje red čekanja naveden kao default na odabranoj vezi. Ako želite odrediti prioritet, možete proslijediti više redova čekanja odvojenih zarezima:
php artisan queue:work redis --queue=high,default,low
Na ovaj način, radnik prvo obrađuje high , zatim default , i tek onda low , što je ključno kada je sistem opterećen i ne želite da 30-minutni izvještaj blokira e-poruke visokog prioriteta.
Drajveri reda čekanja i preduvjeti
Laravel nudi objedinjeni API za nekoliko drajvera reda čekanja , ali svaki ima svoje specifične karakteristike i zavisnosti. Odabir pravog drajvera je ključan prije rasprave o pauziranju workera.
Baza podataka vozača
Vozač baza podataka Pohranjuje poslove u SQL tabelu (obično jobsLako se postavlja i savršeno je za male projekte ili razvojna okruženja gdje se ne želite petljati s Redisom ili SQS-om.
Osnovni koraci:
- Generišite migraciju:
php artisan queue:table(ili u novijim verzijama, dolazi kaocreate_jobs_tablezadano). - Pokreni migracije:
php artisan migrate. - Postavite QUEUE_CONNECTION=baza podataka u
.envi potvrdite uconfig/queue.phpQue'default' => env('QUEUE_CONNECTION','database').
Dovoljno je praktično i robusno, ali s mnogo redova čekanja i puno prometa može postati usko grlo , jer sve prolazi kroz istu relacijsku bazu podataka.
Drajver Redis
Redis drajver je standardni radni konj u produkciji. Brz je, podržava napredne funkcije (zaključavanje, ograničavanje brzine, atomske brave, Horizon, itd.) i vrlo dobro se skalira.
Važne tačke:
- Potrebno je konfigurirati Redis vezu u
config/database.php. - Opcije
serializerycompressioniz Redisa Nisu kompatibilni sa vozačem reda. - Ako koristite Redis klasterNazivi redova moraju imati hashtag, na primjer
{default}tako da svi ključevi u tom redu čekanja padnu u isti slot. - Opcija
block_forOmogućava radniku da blokira proces dok čeka na zadatke nekoliko sekundi, umjesto kontinuiranog ispitivanja: štedi CPU i smanjuje upite prema Redis serveru.
Na primjer:
'redis' => ,
Ako stavite blok_za = 0Radnik ostaje blokiran na neodređeno vrijeme dok se posao ne oslobodi, što treba imati na umu ako želite da brzo reaguje na signale poput SIGTERM ili pauziranje komandi.
Ostali drajveri: SQS, Beanstalkd, null, prebacivanje na drugi sistem…
Pored baza podataka i Redisa, Laravel podržava i druge sisteme :
- Amazon SQSUpravljani redovi čekanja na AWS-u, s podrškom za FIFOGrupe poruka, deduplikacija i napredne postavke vidljivosti. Zahtijeva SDK.
aws/aws-sdk-php. - Stabljika grahaVrlo brzo i jednostavno, korištenjem paketa
pda/pheanstalk. - sinkronizirati: obavlja zadatke inmediatamente u istom procesu. Korisno u razvoju ili testiranju, ali u produkciji je praktično kao da se redovi čekanja uopće ne koriste.
- nullOdbacuje poslove čim budu "otpremljeni". Koristi se za potpuno onemogućavanje sistema čekanja.
- prelazak na greškuOvo vam omogućava da konfigurišete više konekcija, a ako primarna ne uspije, Laravel pokušava da preusmjeri posao na sljedeću na listi. Savršeno za okruženja gdje visoka dostupnost je kritičan.
Na nivou pauziranja i nastavka rada radnika, logika je praktično ista bez obzira na drajver, jer se njome upravlja iz Artisan komandi i klase Radnik , a ne iz pozadinskog sistema reda čekanja.
Kreiranje poslova i serijalizacija modela
Un posao U Laravelu, to je jednostavno klasa koja enkapsulira zadatak koji se izvršava u redu čekanja. Obično se generira pomoću Artisana i sprema u app/Jobs.
Da biste ga kreirali:
php artisan make:job ProcessPodcast
Generisana klasa implementira ShouldQueue i obično koristi osobine Dispatchable, InteractsWithQueue, Queueable y SerializesModelsSrce je u metodi handle()što je ono što radnik radi kada posao stigne.
Posebno moćna funkcija je automatska serijalizacija Eloquent modela . Ako prihvatite model u konstruktoru posla, Laravel ne dodaje cijeli objekt u red čekanja, već samo njegov identifikator. Kada se posao obradi, rekonstruiše model iz baze podataka sa učitanim odnosima.
Tipičan primjer (u pseudokodu, kako bi se izbjeglo doslovno ponavljanje):
- Graditelj prima Podcast $podcast.
- Osobina
SerializesModelsOdgovoran je za spremanje identifikacionog broja. - En
handle(AudioProcessor $processor)Vi obavljate težak posao (na primjer, obradu zvuka).
Ako ne želite da se odnosi u modelu serijaliziraju (kako bi korisni teret bio ogroman), možete koristiti $model->withoutRelations() ili u PHP 8 atribut # na promovisanom posjedu graditelja.
Ubrizgavanje zavisnosti u metodu handle
Još jedna prednost je što možete ubrizgaj usluge direktno u metodu handle (kao da je kontroler), jer Laravel također koristi kontejner servisa u Jobs-u. Na primjer, možete zatražiti AudioProcessorHTTP klijenti, repozitorij itd., a okvir se brine o njihovom rješavanju.
Ako vam je potrebna ultra-fina kontrola onoga što se naziva handlemožete koristiti Container::bindMethod() kod pružatelja usluga i sami definirajte logiku ubrizgavanja, ali u većini slučajeva nema potrebe toliko komplicirati stvari.
Middleware za poslove
Kao što rute imaju middleware, tako i poslovi mogu imati specifični middleware koji se izvršavaju prije i poslije zadatka. Ovo uveliko smanjuje ponavljajući kod u metodama handle() a posebno je koristan za:
- Ograničavanje brzine sa Redisom.
- Izbegavajte preklapanja djela koja se dotiču istog resursa.
- Redovni izuzeci za nestabilne API-je.
- Preskakanje poslova pod određenim uslovima (
Skipsrednji softver).
Middleware se obično postavlja u app/Jobs/Middleware i vraćaju se iz metode middleware() Iz knjige Job. Konceptualni primjer:
public function middleware(): array { return ;
Posebne vrste poslova: jedinstveni, šifrirani i zaključani
Laravel vam omogućava da označite određene poslove kao jedinstven kako bi se osiguralo da se nijedne dvije identične instance nikada ne stave u red čekanja u isto vrijeme. To se postiže implementacijom interfejsa ShouldBeUnique o ShouldBeUniqueUntilProcessingi podržava definiranje ključa uniqueId() i vrijeme uniqueFor.
Ovo je idealno za stvari poput:
- Ponovo izračunajte indeks pretrage proizvoda: samo jednom po proizvodu dok ne završi.
- Sinhronizacije sa eksternim servisima koji ne dozvoljavaju istovremene zahtjeve za isti resurs.
Ispod, Laravel koristi atomska brava keš memorije (Redis, memcached, baza podataka, itd.). Također možete odabrati drajver keš memorije za tu bravu pomoću uniqueVia().
Osim toga, tu je i interfejs ShouldBeEncrypted, čime označavate da je potpuni Posao Unesite svoj kod prije ulaska u red čekanjaVeoma korisno prilikom prenosa osjetljivih podataka, a ne želite da se oni prenose kao običan tekst kroz Redis, SQS ili bazu podataka.
Slanje, odlaganje i izvršavanje poslova u različitim režimima
Nakon što je vaš posao definiran, pokrećete ga sa Job::dispatch() od kontrolera, slušača događaja, Artisan komandi ili čak zatvaranja. Parametri koje prosljeđujete dispatch Idu direktno graditelju Joba.
Zanimljive varijacije:
dispatchIf()ydispatchUnless()da se pošiljka uslovno pakuje u jednu liniju.delay()tako da se posao ne može obraditi do određenog datuma/vremena.dispatchAfterResponse()oafterResponse()endispatch()Zatvaranja, koja odlažu izvršenje dok se ne pošalje HTTP odgovor, ali unutar istog PHP procesa.dispatchSync()da se Posao pokrene sinhrono (bez prolaska kroz red čekanja), ali ponovo koristeći istu klasu.- Specijalne veze kao što su
deferredobackgroundizvršiti nakon odgovora, u istom procesu ili u novom PHP procesu.
Konačno, možete odrediti vezu i red čekanja pomoću ulančanih metoda. onConnection() y onQueue(), bilo prilikom otpreme ili unutar alata za izradu poslova.
Fina kontrola: ponovni pokušaji, odgoda, vremenska ograničenja i rukovanje greškama
Veliki dio rada s redovima čekanja u Laravelu je odlučivanje koliko puta treba ponovo pokušati izvršiti zadatak , koliko dugo treba čekati između pokušaja i kada ga smatrati neuspjehom.
Dostupne opcije:
--triesenqueue:workpostaviti maksimalan broj pokušaja za sve zadatke tog radnika (osim ako zadatak ne definira svoj vlastiti)$triesotries()).$triesili metodatries()u klasi Job za kontrolu po zadatku.retryUntil()reći: „pokušavaj ponovo koliko god želiš do ovog puta, nakon toga, to je neuspjeh.“ Ako se poklopi satries, naredbaretryUntil.$maxExceptionsda se prekine kada je problem uzrokovan ponovljenim neobrađenim izuzecima.$timeouto--timeoutda bi se naznačilo koliko sekundi posao može da se izvršava prije nego što radnik završi podređeni proces.$failOnTimeoutoznačiti zadatak kao neuspješan u slučaju isteka vremena.$backoffmetodabackoff()definirati koliko dugo treba čekati između ponovnih pokušaja, čak i s eksponencijalnim vrijednostima.
Ako posao izbaci neuhvaćeni izuzetak, Laravel će... ispušta se nazad u rep dok se ne iscrpe konfigurisani pokušaji. Ovo možete ručno kontrolisati pomoću release($segundos) o fail($exception) kada želite namjerno označiti posao kao neuspješan.
Neuspjeli poslovi, tabela failed_jobs i skraćivanje
Kada Job iscrpi svoje pokušaje, počinje se smatrati neuspjeli rad i Laravel ga ubacuje u tabelu failed_jobs (ili u DynamoDB-u ako ga tako konfigurirate). Ta tabela pohranjuje UUID, vezu, red čekanja, korisni teret posla i izuzetak koji je izbačen.
Korisne naredbe:
php artisan queue:failedda navedem one koji nisu uspjeli.php artisan queue:retry <id|all>da ih ponovo probam.php artisan queue:forget <id>da izbrišete jedan.php artisan queue:flushza brisanje svih (s opcijom za sate u novijim verzijama).php artisan queue:prune-failed --hours=48za automatsko brisanje starih zapisa.
U odjeljku Poslovi možete definirati metodu failed(Throwable $exception) Za dodatno čišćenje: obavijestite korisnika, poništite djelomične radnje, zapišite specijalizirane zapise itd. Imajte na umu da se nova instanca zadatka kreira za pozivanje failed()Stoga se nemojte oslanjati na promjene na imovini napravljene u handle().
Grupiranje poslova: serije poslova i njihovo kombinovanje pomoću stringova
Kada trebate pokrenuti stotine ili hiljade povezanih poslova (na primjer, uvoz ogromnog CSV-a u dijelovima, obrada datoteka u serijama, čišćenje podataka itd.), preporučljivo je koristiti Laravelovu funkcionalnost serija .
Osnovni tok:
- kreirajte tabelu
job_batchesconphp artisan queue:batches-table && php artisan migrate. - Označite poslove koji će biti dio serija sa osobinom
Batchable. - Usar
Bus::batch()za slanje skupa poslova, s povratnim pozivimathen,catchyfinally. - Pristupite seriji iz svakog posla sa
$this->batch()i provjerite da li je otkazano. - Mogućnost dodavanja više poslova u tekuću seriju sa
$this->batch()->add().
Serije se lijepo integriraju s lancima : možete imati lance unutar serije ili serije kao elemente većeg lanca. Ovo je posebno korisno kada želite da više lanaca radi "paralelno" i pokrene nešto kada se svi završe.
Izvršenje, prioriteti i raspoređivanje radnika
Sva magija redova se dešava zato što imate jedan ili više radnika izvođenje naredbe queue:work (o queue:listen(iako je ovo drugo manje efikasno). Ovi procesi su dugotrajni demoni koji osluškuju svoje odgovarajuće redove čekanja.
Ključne opcije queue:work:
- Connection:
php artisan queue:work redis,queue:work database, Itd - Repovi:
--queue=high,default,lowodrediti prioritete. - -jedanaest: obrađuje jedan zadatak i izlazi.
- –max-jobs: obrađuje X poslova i završava (da bi se periodično ponovo pokrenuli radnici i oslobodila memorija).
- –maksimalno vrijeme: obrađuje se N sekundi, a zatim se završava.
- –san: sekunde čekanja kada nema dostupnih poslova.
- –zaustavi-kada-je-prazno: prazni red i čisto zatvara (idealno u Docker okruženjima ili jednokratnim poslovima).
- –timeout: sekunde vremenskog ograničenja po zadatku, kao što smo već spomenuli.
- –Force: za obradu poslova čak i ako je aplikacija u načinu održavanja.
Budući da se ovi procesi dugo izvršavaju, u produkciji se gotovo uvijek koristi monitor procesa poput Supervisora (na Linuxu) za pokretanje X workera, njihovo ponovno pokretanje ako se sruše i upravljanje logovima. Tipičan konfiguracijski blok Supervisora za Laravel definira:
- naredba sa
php artisan queue:work ...beton. - brojprocesa da naznači koliko radnika treba pokrenuti paralelno.
- Putanje zapisnika, korisnik, automatsko ponovno pokretanje itd.
Pauziranje i nastavljanje redova čekanja u Laravelu
Prijeđimo na ono što je često važno u održavanju: kako pauzirati radnike u redu čekanja bez njihovog naglog zaustavljanja i bez ostavljanja poslova nedovršenim. Laravel nudi nekoliko mehanizama, neke novije, neke klasične, za kontrolu ovoga.
Pauza: red čekanja: signali pauze i prekida
U novijim verzijama, Laravel dodaje specifične naredbe za pauziranje i nastavak izvršavanja workera:
php artisan queue:pause: govori sistemu da prestane preuzimati nove poslove, ali da pusti one koji su već u toku da se završe.php artisan queue:continue: nastavlja obradu novih poslova od mjesta gdje je stala.
Ove naredbe rade slanjem signala radnicima putem mehanizma keširanja koji Laravel interno koristi. Zato je važno imati pravilno konfiguriran drajver keša (memcached, redis, database, file, itd.) čak i ako je vaš stvarni red keša nešto drugo.
Važno: Pauziranje reda čekanja ili radnika ne otkazuje niti briše poslove koji su već u redu čekanja ; jednostavno sprječava uklanjanje daljnjih poslova iz reda čekanja dok pauza traje.
Anketiranje poremećaja i utjecaja na performanse
Svaki put kada radnik završi posao, Laravel provjerava keš memoriju za signale za ponovno pokretanje, pauziranje ili nastavak . Ovo ima zanemarljivu cijenu, ali postoji. Ako ste izuzetno fokusirani na performanse i znate da nećete morati pauzirati ili ponovo pokretati radnike iz naredbi, možete onemogućiti ovo ispitivanje pozivom:
Queue::withoutInterruptionPolling();
Ili čak prilagodite statička svojstva Illuminate\Queue\Worker da biste onemogućili određene dodire ($restartable, $pauzableMeđutim, ako to uradite, a zatim pokušate koristiti queue:pause o queue:restartradnici Neće saznatiTo je dizajnerska odluka koju treba pažljivo razmotriti.
Ručno pauziranje pomoću Supervisora ili Dockera
Pored Laravelovih vlastitih naredbi , u produkcijskim okruženjima, procesi se često indirektno "pauziraju":
- Zaustavljanje programa u Supervisoru (
supervisorctl stop laravel-worker:*), što ubija ili zaustavlja radnike. - Upotreba –zaustavi-kada-je-prazno u raspoređivanjima kako bi radnici završili ono što je u redu čekanja, a zatim se isključili.
- U Dockeru, omogućavanje kontejneru da obrađuje sa
--stop-when-emptya onda se isključuje.
Razlika sa queue:pause Potpunim zaustavljanjem procesa, zaustavit ćete obradu poslova dok se radnici ponovo ne pokrenu. unutrašnja pauza Možete čuvati procese u memoriji, čekajući naredbu continueOvo je korisno za brza vraćanja na prethodno stanje ili kratke periode održavanja.
Transakcije baze podataka i after_commit
Klasična greška: slanje poslova unutar transakcija baze podataka . Ako niste pažljivi, radnik bi mogao izvršiti posao prije nego što se izvrši potvrda (commit), a model ili podaci koje očekujete možda još nisu u bazi podataka.
Da biste izbjegli ovaj ples, imate dvije mogućnosti:
- Aktivirajte
'after_commit' => trueu konfiguraciji veze reda čekanja. Stoga se svaki posao poslan unutar transakcije interno odlaže dok se ne potvrdi. - Koristite metode za svaki pojedinačni posao
afterCommit()obeforeCommit()prilikom otpremanja, da bi se ponašanje nametnulo samo u određenim poslovima (Jobs).
Ako se transakcija poništi, poslovi poslani tokom nje se odbacuju bez ulaska u red čekanja, što je upravo ono što se obično želi postići radi održavanja konzistentnosti.
Praćenje, čišćenje reda čekanja i testiranje
Kada jednom ozbiljno pokrenete redove čekanja, nije dovoljno samo odbaciti poslove i zaboraviti na njih; trebali biste pratiti i testirati kako se sve ponaša.
Korisni alati i naredbe:
queue:clearda se isprazni određeni red čekanja (SQS, Redis, baza podataka).queue:monitorpratiti broj poslova u određenim redovima čekanja i pokrenuti događajQueueBusyako pređu određeni prag.- Događaji za posao como
Queue::before,Queue::after,Queue::loopingyQueue::failingza povezivanje prilagođene logike (logovi, metrike, vraćanje prethodnih promjena itd.). - Falsifikati u testiranju koristeći
Queue::fake()yBus::fake()kako bi se provjerilo da li su poslovi, nizovi znakova ili serije poslani bez njihovog stvarnog izvršavanja.
U testovima možete navesti stvari poput „ovaj posao je stavljen u red čekanja X puta“ , „lanac s ovim poslovima je poslan ovim redoslijedom“ ili „nijedan određeni posao nije stavljen u red čekanja“, što pruža mnogo sigurnosti u složenim tokovima.
Sa cijelim ovim ekosistemom - drajverima poput Redisa ili SQS-a, dobro dizajniranim poslovima, middlewareom za fino podešavanje, serijama, lancima, konfiguracijom ponovnog pokušaja, radnicima kojima upravlja supervizor i naredbama poput queue:pause y queue:continue— Laravel vam omogućava da savladate pozadinsku obradu do milimetra, od tipičnog slanja e-pošte do distribuiranih arhitektura redova čekanja s prebacivanjem u slučaju kvara, osiguravajući da vaša aplikacija nastavi brzo reagirati na HTTP sloju dok se ispod obavlja težak posao bez blokiranja korisnika.