- Laravel nudi objedinjeni API za redove s više upravljačkih programa (baza podataka, Redis, SQS…) i odvajanjem između veza i logičkih redova.
- Poslovi omogućuju premještanje zahtjevnih zadataka u pozadinu, uz podršku za serijalizaciju modela, middleware, jednokratne poslove, šifriranje, serije i nizove znakova.
- 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 ekosustav za kvarove, praćenje i testiranje (failed_jobs, queue:retry, queue:monitor, Queue::fake) koji redove čini pouzdanima u produkciji.
Rad s redovima čekanja u Laravelu gotovo je 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 radi 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 snažnu i fleksibilnu infrastrukturu čekanja koja vam omogućuje delegiranje teškog rada pozadinskim procesima, upravljanje njima prema prioritetu, grupiranje u serije, praćenje, ponovni pokušaj kada ne uspiju, pa čak i privremeno pauziranje workera radi održavanja. Pogledajmo pobliže (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 pojmovi: veze, redovi čekanja i upravljački programi
U Laravelu, prije nego što išta pauzirate, morate razumjeti razliku između veze redova čekanja i sami redovi čekanja. U config/queue.php imaš niz connections gdje definirate svaki backend: baza podataka, redis, beanstalkd, sqs, sinkronizacija, null, prebacivanje na drugi sustav, 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 učiniti stvari poput:
- Brzi red za e-poruke ili kratke transakcije.
- Još jedan nizak prioritet za duge zadatke poput obrade videozapisa ili velikih izvješća.
- Redovi segmentirani prema vrsti zadatka:
imports,notificaciones,reportes, Itd
Kada pokrenete radnika s php artisan queue:workPrema zadanim postavkama, osluškuje red čekanja naveden kao zadano na odabranoj vezi. Ako želite odrediti prioritete, 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 sustav opterećen i ne želite da 30-minutno izvješće blokira e-poruke visokog prioriteta.
Upravljački programi reda čekanja i preduvjeti
Laravel nudi objedinjeni API za nekoliko upravljačkih programa reda čekanja , ali svaki ima svoje specifične značajke i ovisnosti. Odabir pravog upravljačkog programa ključan je prije rasprave o pauziranju workera.
Baza podataka vozača
Vozač baza podataka Pohranjuje poslove u SQL tablicu (obično jobsJednostavno ga je postaviti i savršeno je za male projekte ili razvojna okruženja gdje se ne želite petljati s Redisom ili SQS-om.
Osnovni koraci:
- Generiraj migraciju:
php artisan queue:table(ili u novijim verzijama, dolazi kaocreate_jobs_tablezadano). - Pokreni migracije:
php artisan migrate. - konfiguriranje QUEUE_CONNECTION=baza podataka u
.envi potvrditi uconfig/queue.phpovo'default' => env('QUEUE_CONNECTION','database').
Dovoljno je praktično i robusno, ali s mnogo redova čekanja i puno prometa može postati usko grlo , budući da sve prolazi kroz istu relacijsku bazu podataka.
Vozač Redis
Redis upravljački program je standardni radni stroj u produkciji. Brz je, podržava napredne značajke (zaključavanje, ograničavanje brzine, atomske brave, Horizon itd.) i vrlo dobro se skalira.
Važne točke:
- Morate konfigurirati Redis vezu u
config/database.php. - Opcije
serializerycompressioniz Redisa Nisu kompatibilni s 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 utor. - Izbor
block_forOmogućuje radniku da blokira dok čeka poslove nekoliko sekundi, umjesto kontinuiranog ispitivanja: štedi CPU i smanjuje upite prema Redis poslužitelju.
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 reagira na signale poput SIGTERM ili pauziranje naredbi.
Ostali upravljački programi: SQS, Beanstalkd, null, prebacivanje na drugi sustav…
Osim baza podataka i redisa, Laravel podržava i druge sustave :
- 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 odmah u istom procesu. Korisno u razvoju ili testiranju, ali u produkciji je praktički kao da uopće ne koristite redove čekanja.
- nula: Odbacuje poslove čim se "otpreme". Koristi se za potpuno onemogućavanje sustava čekanja.
- prelazak na kvarTo vam omogućuje konfiguriranje više veza, a ako primarna ne uspije, Laravel pokušava prenijeti posao na sljedeću na popisu. Savršeno za okruženja gdje visoka dostupnost je kritičan.
Na razini pauziranja i nastavka rada radnika, logika je praktički ista bez obzira na upravljački program, jer se njome upravlja iz Artisan naredbi i klase Radnik , a ne iz pozadinskog sustava reda čekanja.
Stvaranje 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 izradili:
php artisan make:job ProcessPodcast
Generirana klasa provodi ShouldQueue i obično koristi osobine Dispatchable, InteractsWithQueue, Queueable y SerializesModelsSrce je u metodi handle()što radnik i radi kada posao stigne.
Posebno moćna značajka 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, rekonstruira model iz baze podataka s učitanim odnosima.
Tipičan primjer (u pseudokodu, kako bi se izbjeglo doslovno ponavljanje):
- Graditelj prima Podcast $podcast.
- Osobina
SerializesModelsOdgovoran je za spremanje ID-a. - 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 promoviranoj imovini graditelja.
Ubrizgavanje ovisnosti u metodu handle
Još je jedna prednost što možete ubrizgaj usluge izravno u metodu handle (kao da je kontroler), jer Laravel također koristi kontejner usluga u Jobs. Na primjer, možete zatražiti AudioProcessorHTTP klijenti, repozitoriji itd., a okvir se brine za njihovo rješavanje.
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 Jobs mogu imati specifičan middleware koji se izvode prije i poslije zadatka. To uvelike smanjuje ponavljajući kod u metodama handle() a posebno je koristan za:
- Ograničavanje brzine s Redisom.
- izbjegavati preklapanja djela koja se dotiču istog izvora.
- Redovite iznimke za nestabilne API-je.
- Preskakanje poslova pod određenim uvjetima (
Skipmeđuprogram).
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ćuje označavanje određenih poslova kao jedinstven kako bi se osiguralo da se niti dvije identične instance ne stave u red čekanja istovremeno. To se postiže implementacijom sučelja ShouldBeUnique o ShouldBeUniqueUntilProcessingi podržava definiranje ključa uniqueId() i vrijeme uniqueFor.
Ovo je idealno za stvari poput:
- Ponovno izračunajte indeks pretraživanja proizvoda: samo jednom po proizvodu dok ne završi.
- Sinkronizacije s vanjskim servisima koji ne dopuštaju istovremene zahtjeve za isti resurs.
Ispod, Laravel koristi atomska brava predmemorije (Redis, memcached, baza podataka itd.). Također možete odabrati upravljački program predmemorije za tu bravu pomoću uniqueVia().
Osim toga, tu je i sučelje ShouldBeEncrypted, čime označavate da je cijeli Posao Unesite svoj kod prije ulaska u red čekanjaVrlo korisno prilikom prosljeđivanja osjetljivih podataka, a ne želite da putuju kao običan tekst kroz Redis, SQS ili bazu podataka.
Slanje, odgađanje i izvršavanje poslova u različitim načinima rada
Nakon što je vaš posao definiran, pokrećete ga s Job::dispatch() od kontrolera, slušača događaja, Artisan naredbi ili čak zatvaranja. Parametri koje prosljeđujete dispatch Idu direktno graditelju Joba.
Zanimljive varijacije:
dispatchIf()ydispatchUnless()uvjetovati pošiljku u jednom redu.delay()tako da se posao ne može obraditi do određenog datuma/vremena.dispatchAfterResponse()oafterResponse()endispatch()Zatvaranja, koja odgađaju izvršenje dok se ne pošalje HTTP odgovor, ali unutar istog PHP procesa.dispatchSync()sinkrono izvršavati posao (bez prolaska kroz red čekanja), ali ponovno koristeći istu klasu.- Posebne 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 ponovno pokušati izvršiti zadatak , koliko dugo čekati između pokušaja i kada ga smatrati neuspjehom.
Dostupne opcije:
--triesenqueue:workpostaviti maksimalni broj pokušaja za sve poslove tog radnika (osim ako posao ne definira svoj vlastiti)$triesotries()).$triesili metodatries()u klasi Job za kontrolu po poslu.retryUntil()reći: „pokušavaj ponovno koliko god želiš do ovog puta, nakon toga je to neuspjeh.“ Ako se poklopi stries, naredbaretryUntil.$maxExceptionsprekinuti kada je problem uzrokovan ponovljenim neobrađenim iznimkama.$timeouto--timeoutkako bi se naznačilo koliko sekundi Job može raditi prije nego što radnik ubije podređeni proces.$failOnTimeoutoznačiti posao kao neuspješan u slučaju isteka vremena.$backoffmetodabackoff()definirati koliko dugo čekati između ponovnih pokušaja, čak i s eksponencijalnim vrijednostima.
Ako posao izbaci neuhvaćenu iznimku, Laravel će... ispušta se natrag u rep dok se ne iscrpe konfigurirani pokušaji. To možete ručno kontrolirati pomoću release($segundos) o fail($exception) kada želite namjerno označiti posao kao neuspješan.
Neuspjeli poslovi, tablica failed_jobs i odrezivanje
Kad Job iscrpi svoje pokušaje, počinje se smatrati neuspjeli rad i Laravel ga ubacuje u tablicu failed_jobs (ili u DynamoDB-u ako ga tako konfigurirate). Ta tablica pohranjuje UUID, vezu, red čekanja, teret posla i iznimku koja je bačena.
Korisne naredbe:
php artisan queue:failednavesti one koji nisu uspjeli.php artisan queue:retry <id|all>da ih ponovno isprobam.php artisan queue:forget <id>izbrisati 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 Poslovima možete definirati metodu failed(Throwable $exception) Za dodatno čišćenje: obavijestite korisnika, poništite djelomične radnje, zapišite specijalizirane zapisnike itd. Imajte na umu da se stvara nova instanca zadatka za pozivanje failed()Stoga se nemojte oslanjati na promjene imovine napravljene u handle().
Grupiranje poslova: serije poslova i njihovo kombiniranje s nizovima znakova
Kada trebate pokrenuti stotine ili tisuće povezanih poslova (na primjer, uvoz velikog CSV-a u dijelovima, obrada datoteka u serijama, čišćenje podataka itd.), preporučljivo je koristiti Laravelovu funkcionalnost serija .
Osnovni tok:
- kreirajte tablicu
job_batchessphp artisan queue:batches-table && php artisan migrate. - Označite poslove koji će biti dio serija s osobinom
Batchable. - upotreba
Bus::batch()poslati skup poslova s povratnim pozivimathen,catchyfinally. - Pristupite seriji iz svakog posla s
$this->batch()i provjerite je li otkazano. - Mogućnost dodavanja više poslova u tekuću seriju s
$this->batch()->add().
Serije se prekrasno integriraju s lancima : možete imati lance unutar serije ili serije kao elemente većeg lanca. To 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 čarolija redova događa se zato što imate jedan ili više radnika pokretanje naredbe queue:work (o queue:listen(iako je potonji manje učinkovit). Ovi procesi su dugotrajni demoni koji osluškuju svoje redove čekanja.
Ključne opcije queue:work:
- Priključak:
php artisan queue:work redis,queue:work database, Itd - Colas:
--queue=high,default,lowodrediti prioritete. - -jedanaest: obrađuje jedan zadatak i izlazi.
- –max-jobs: obrađuje X poslova i završava (kako bi se periodično ponovno pokrenuli radnici i oslobodila memorija).
- –maksimalno vrijeme: obrađuje se N sekundi, a zatim izlazi.
- -spavati: 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.
- -sila: za obradu poslova čak i ako je aplikacija u načinu održavanja.
Budući da se ovi procesi dugo izvode, 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 zapisnicima. Tipičan konfiguracijski blok Supervisora za Laravel definira:
- naredba s
php artisan queue:work ...betonske. - brojprocesa kako bi se naznačilo koliko radnika treba pokrenuti paralelno.
- Putanje zapisnika, korisnik, automatska ponovna pokretanja itd.
Pauziranje i ponovno pokretanje redova čekanja u Laravelu
Prijeđimo na ono što je često važno u održavanju: kako pauzirati radnike u redu čekanja bez naglog zaustavljanja i bez ostavljanja poslova nedovršenima. 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 sustavu da prestane preuzimati nove poslove, ali da pusti one koji su već u tijeku da se završe.php artisan queue:continue: nastavlja obradu novih poslova od mjesta gdje je stao.
Ove naredbe rade slanjem signala radnicima putem mehanizma predmemorije koji Laravel interno koristi. Zato je važno imati ispravno konfiguriran upravljački program predmemorije (memcached, redis, database, file itd.) čak i ako je vaš stvarni red predmemorije nešto drugo.
Važno: Pauziranje reda ili radnika ne poništava niti briše poslove koji su već u redu ; jednostavno sprječava uklanjanje daljnjih poslova iz reda dok pauza traje.
Anketiranje poremećaja i utjecaj na performanse
Svaki put kada radnik završi posao, Laravel provjerava predmemoriju za signale za ponovno pokretanje, pauziranje ili nastavak . To ima zanemariv trošak, ali postoji. Ako ste izuzetno usredotočeni na performanse i znate da nećete trebati pauzirati ili ponovno pokretati radnike iz naredbi, možete onemogućiti ovo ispitivanje pozivom:
Queue::withoutInterruptionPolling();
Ili čak prilagoditi statička svojstva Illuminate\Queue\Worker za onemogućavanje određenih dodira ($restartable, $pauzableMeđutim, ako to učinite, 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
Uz Laravelove vlastite naredbe , u produkcijskim okruženjima, procesi se često neizravno "pauziraju":
- Zaustavljanje programa u Supervisoru (
supervisorctl stop laravel-worker:*), što ubija ili zaustavlja radnike. - koristeći –zaustavi-kada-je-prazno u implementacijama kako bi radnici završili ono što je u redu čekanja, a zatim se isključili.
- U Dockeru, puštanje kontejnera da obrađuje s
--stop-when-emptya onda se ugasi.
Razlika sa queue:pause Potpunim zaustavljanjem procesa zaustavit ćete obradu poslova dok se radnici ponovno ne pokrenu. unutarnja pauza Procese možete držati u memoriji, čekajući naredbu continueOvo je korisno za brza vraćanja na prethodno stanje ili kratka razdoblja održavanja.
Transakcije baze podataka i after_commit
Klasična greška: slanje poslova unutar transakcija baze podataka . Ako niste oprezni, 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:
- Aktivirati
'after_commit' => trueu konfiguraciji veze reda čekanja. Stoga se svaki posao poslan unutar transakcije interno odgađa dok se ne potvrdi. - Koristite metode za svaki posao
afterCommit()obeforeCommit()prilikom otpreme, kako bi se ponašanje prisililo samo u određenim poslovima.
Ako se transakcija poništi, poslovi poslani tijekom 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
Nakon što 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:clearisprazniti određeni red (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 kao
Queue::before,Queue::after,Queue::loopingyQueue::failingza povezivanje prilagođene logike (logovi, metrike, vraćanja na prethodno stanje itd.). - Krivotvorine u testiranju pomoću
Queue::fake()yBus::fake()kako bi se provjerilo jesu li poslovi, nizovi znakova ili serije poslani bez njihovog stvarnog izvršenja.
U testovima možete navesti stvari poput „ovaj je posao stavljen u red čekanja X puta“ , „lanac s ovim poslovima poslan je ovim redoslijedom“ ili „nijedan određeni posao nije stavljen u red čekanja“, što pruža veliku sigurnost u složenim tokovima.
S cijelim ovim ekosustavom - upravljačkim programima poput Redisa ili SQS-a, dobro dizajniranim poslovima, middlewareom za fino podešavanje, serijama, lancima, konfiguracijom ponovnog pokušaja, radnicima kojima upravlja nadzornik i naredbama poput queue:pause y queue:continue— Laravel vam omogućuje da savladate pozadinsku obradu do milimetra, od tipičnog slanja e-pošte do distribuiranih arhitektura redova 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.