- Laravel tilbyr et enhetlig kø-API med flere drivere (database, Redis, SQS…) og separasjon mellom tilkoblinger og logiske køer.
- Jobber lar tunge oppgaver flyttes til bakgrunnen, med støtte for serialisering av modeller, mellomvare, engangsjobber, kryptering, batcher og strenger.
- Arbeidere administreres med queue:work, Supervisor og kommandoer som queue:pause/queue:continue, som kontrollerer nye forsøk, tidsavbrudd og prioriteringer.
- Det finnes et komplett økosystem for feil, overvåking og testing (failed_jobs, queue:retry, queue:monitor, Queue::fake) som gjør køer pålitelige i produksjon.
Å jobbe med køer i Laravel er nesten obligatorisk i ethvert halvveis seriøst prosjekt: sending av e-poster, behandling av CSV-filer, generering av PDF-er, endring av størrelse på bilder, kalling av eksterne API-er ... Hvis alt dette gjøres i den primære HTTP-forespørselen, blir nettstedet tregt, 500 feil dukker opp, og brukeren ender opp med å stirre desperat på en blank skjerm.
Den gode nyheten er at Laravel tilbyr en kraftig og fleksibel køinfrastruktur som lar deg delegere tunge løft til bakgrunnsprosesser, administrere dem etter prioritet, gruppere dem i batcher, overvåke dem, prøve dem på nytt når de feiler, og til og med midlertidig sette arbeidere på pause for vedlikehold. La oss ta en nærmere titt (og ikke utelate noe) på hvordan du får mest mulig ut av det, inkludert hvordan du pauser, gjenopptar og kontrollerer oppførselen i produksjon.
Grunnleggende konsepter: tilkoblinger, køer og drivere
I Laravel, før du setter noe på pause, må du forstå forskjellen mellom køforbindelser og selve køene. i config/queue.php du har en matrise connections hvor du definerer hver backend: database, redis, beanstalkd, sqs, synkronisering, null, failover, rabbitmq (hvis du legger det til), osv.
Hver forbindelse kan ha flere logiske køer (navn som default, emails, high, low, importsAttributtet queue Hver tilkobling angir hvilken standardkø jobbene skal havne i hvis ingen annen er spesifisert. onQueue()På denne måten kan du gjøre ting som:
- En rask kø for e-poster eller korte transaksjoner.
- En annen lav prioritet for lange oppgaver som behandling av videoer eller store rapporter.
- Køer segmentert etter oppgavetype:
imports,notificaciones,reportesOsv
Når du starter arbeideren med php artisan queue:workSom standard lytter den til køen som er spesifisert som misligholde på den valgte tilkoblingen. Hvis du vil prioritere, kan du sende flere kommaseparerte køer:
php artisan queue:work redis --queue=high,default,low
På denne måten behandler arbeideren high først , deretter default , og bare deretter low , noe som er avgjørende når systemet er lastet og du ikke vil at en 30-minutters rapport skal blokkere e-poster med høy prioritet.
Kødrivere og forutsetninger
Laravel tilbyr et enhetlig API for flere kødrivere , men hver har sine egne spesifikke funksjoner og avhengigheter. Å velge riktig driver er avgjørende før man diskuterer å sette arbeidere på pause.
Sjåførdatabase
Sjåføren database Den lagrer jobbene i en SQL-tabell (vanligvis jobsDet er enkelt å sette opp og perfekt for små prosjekter eller utviklingsmiljøer der du ikke vil tukle med Redis eller SQS.
Grunnleggende trinn:
- Generer migreringen:
php artisan queue:table(eller i nyere versjoner kommer den somcreate_jobs_tablemisligholde). - Kjør migreringer:
php artisan migrate. - konfigurering KØFORBINDELSE=database i
.envog bekreftconfig/queue.phpque'default' => env('QUEUE_CONNECTION','database').
Det er praktisk og robust nok, men med mange køer og mye trafikk kan det bli en flaskehals , siden alt går gjennom den samme relasjonsdatabasen.
Driver Redis
Redis -driveren er standard arbeidshesten i produksjon. Den er rask, støtter avanserte funksjoner (låsing, hastighetsbegrensning, atomlåser, Horizon osv.) og skalerer veldig bra.
Viktige punkter:
- Du må konfigurere Redis-tilkoblingen i
config/database.php. - Alternativene
serializerycompressionfra Redis De er ikke kompatible med køsjåføren. - Hvis du bruker Redis-klyngenNavnene på køene må ha en hashtag, for eksempel
{default}slik at alle nøklene i køen faller inn i samme spor. - Alternativet
block_forDet lar arbeideren blokkere mens de venter på jobber i noen sekunder, i stedet for kontinuerlig å avspørre: sparer CPU og reduserer antall spørringer til Redis-serveren.
For eksempel:
'redis' => ,
Hvis du setter blokk_for = 0Arbeideren forblir blokkert på ubestemt tid inntil en jobb blir tilgjengelig, noe du bør huske på hvis du vil at den skal reagere raskt på signaler som SIGTERM eller sette kommandoer på pause.
Andre drivere: SQS, Beanstalkd, null, failover…
I tillegg til databaser og redis støtter Laravel andre systemer :
- Amazon SQSAdministrerte køer på AWS, med støtte for FIFOMeldingsgrupper, deduplisering og avanserte synlighetsinnstillinger. Krever SDK-en.
aws/aws-sdk-php. - BønnestengelVeldig raskt og enkelt å bruke pakken
pda/pheanstalk. - synkronisere: utfører oppgavene umiddelbart i samme prosess. Nyttig i utvikling eller testing, men i produksjon er det praktisk talt som å ikke bruke køer i det hele tatt.
- nullForkaster jobber så snart de er «sendt». Brukes til å deaktivere køsystemet fullstendig.
- failoverDette lar deg konfigurere flere tilkoblinger, og hvis den primære feiler, prøver Laravel å sende jobben til den neste i listen. Perfekt for miljøer der høy tilgjengelighet Det er kritisk.
Når det gjelder å sette arbeidere på pause og gjenoppta dem, er logikken praktisk talt den samme uavhengig av driveren, fordi den administreres fra Artisan-kommandoene og Worker -klassen , ikke fra køens backend.
Jobboppretting og modellserialisering
Un Jobb I Laravel er det rett og slett en klasse som innkapsler en oppgave som skal utføres i en kø. Den genereres vanligvis med Artisan og lagres i app/Jobs.
Slik oppretter du en:
php artisan make:job ProcessPodcast
Den genererte klassen redskaper ShouldQueue og bruker vanligvis egenskaper Dispatchable, InteractsWithQueue, Queueable y SerializesModelsHjertet ligger i metoden handle()som er det arbeideren gjør når jobben kommer.
En spesielt kraftig funksjon er den automatiske serialiseringen av Eloquent-modeller . Hvis du aksepterer en modell i jobbkonstruktøren, legger ikke Laravel til hele objektet i køen, bare identifikatoren. Når jobben er behandlet, rekonstruerer den modellen fra databasen med relasjonene lastet inn.
Typisk eksempel (i pseudokode, for å unngå å gjenta det ordrett):
- Byggmester mottar Podkast $podkast.
- Egenskapen
SerializesModelsDen er ansvarlig for å lagre ID-en. - En
handle(AudioProcessor $processor)Du gjør det harde arbeidet (for eksempel å behandle lyd).
Hvis du ikke vil at relasjonene i en modell skal serialiseres (slik at nyttelasten ikke blir enorm), kan du bruke $model->withoutRelations() eller i PHP 8 attributtet # på eiendommen som er promotert av byggherren.
Avhengighetsinjeksjon i håndtaksmetoden
En annen fordel er at du kan injiser tjenester direkte i håndtaksmetoden (som om det var en kontroller), fordi Laravel også bruker servicecontaineren i Jobs. For eksempel kan du be om en AudioProcessorHTTP-klienter, repositorier osv., og rammeverket tar seg av å løse dem.
Hvis du trenger ultrafin kontroll over det som kalles handledu kan bruke Container::bindMethod() hos en tjenesteleverandør og definere injeksjonslogikken selv, men i de fleste tilfeller er det ikke nødvendig å komplisere ting så mye.
Jobb mellomvare
Akkurat som ruter har mellomvare, kan også jobber ha spesifikk mellomvare som kjører før og etter jobben. Dette reduserer repeterende kode i metodene betraktelig handle() og det er spesielt nyttig for:
- Hastighetsbegrensning med Redis.
- unngå overlappinger av verk som berører den samme ressursen.
- Vanlige unntak for ustabile API-er.
- Hoppe over jobber under visse betingelser (
Skipmellomvare).
Mellomvare plasseres vanligvis i app/Jobs/Middleware og returneres fra metoden middleware() Fra Job. Konseptuelt eksempel:
public function middleware(): array { return ;
Spesielle jobbtyper: unike, krypterte og låste
Laravel lar deg merke bestemte jobber som unik for å sikre at ingen to identiske instanser noen gang står i kø samtidig. Dette oppnås ved å implementere grensesnittet ShouldBeUnique o ShouldBeUniqueUntilProcessingog støtter definering av en nøkkel uniqueId() og en tid uniqueFor.
Dette er ideelt for ting som:
- Beregn et produkts søkeindeks på nytt: bare én gang per produkt til den er ferdig.
- Synkroniseringer med eksterne tjenester som ikke tillater samtidige forespørsler for samme ressurs.
Under bruker Laravel en atomlås av hurtigbuffer (Redis, memcached, database osv.). Du kan også velge hurtigbufferdriveren for den låsen med uniqueVia().
I tillegg er det grensesnittet ShouldBeEncrypted, som du bruker til å angi at hele jobben er Skriv inn koden din før du går inn i køenVeldig nyttig når du sender sensitive data, og du ikke vil at de skal sendes i ren tekst gjennom Redis, SQS eller databasen.
Send, forsink og utfør jobber i forskjellige moduser
Når jobben din er definert, starter du den med Job::dispatch() fra kontrollere, hendelseslyttere, Artisan-kommandoer eller til og med lukkinger. Parametrene du sender til dispatch De går direkte til den som bygger Job.
Interessante variasjoner:
dispatchIf()ydispatchUnless()å kondisjonere forsendelsen i én linje.delay()slik at jobben ikke kan behandles før en bestemt dato/klokkeslett.dispatchAfterResponse()oafterResponse()endispatch()Closures, som utsetter kjøringen til HTTP-svaret er sendt, men innenfor samme PHP-prosess.dispatchSync()å kjøre jobben synkront (uten å gå gjennom køen), men bruke samme klasse på nytt.- Spesielle forbindelser som f.eks.
deferredobackgroundå utføre etter svaret, i samme prosess eller i en ny PHP-prosess.
Til slutt kan du spesifisere tilkobling og kø med kjedede metoder. onConnection() y onQueue(), enten ved utsendelse eller i jobbbyggeren.
Finkontroll: nye forsøk, tilbaketrekking, tidsavbrudd og feilhåndtering
En stor del av det å jobbe med køer i Laravel er å bestemme hvor mange ganger man skal prøve en jobb på nytt , hvor lenge man skal vente mellom forsøkene, og når man skal anse den som en mislykket.
Tilgjengelige alternativer:
--triesenqueue:workfor å angi maksimalt antall forsøk for alle jobber til den arbeideren (med mindre jobben definerer sin egen)$triesotries()).$trieseller en metodetries()i jobbklassen for kontroll per jobb.retryUntil()å si: «prøv igjen så mye du vil helt til denne gangen, etter det, er det fiasko.» Hvis det sammenfaller medtries, kommandoretryUntil.$maxExceptionså kutte av når problemet skyldes gjentatte ubehandlede unntak.$timeouto--timeoutfor å angi hvor mange sekunder en jobb kan kjøre før arbeideren avslutter barneprosessen.$failOnTimeoutfor å markere jobben som mislykket i tilfelle tidsavbrudd.$backoffmetodenbackoff()for å definere hvor lenge det skal ventes mellom nye forsøk, selv med eksponensielle verdier.
Hvis en jobb kaster et uoppdaget unntak, vil Laravel... slippes tilbake i halen inntil de konfigurerte forsøkene er oppbrukt. Du kan kontrollere dette manuelt med release($segundos) o fail($exception) når du bevisst vil markere en jobb som mislykket.
Mislykkede jobber, tabellen failed_jobs og beskjæring
Når en jobb uttømmer hans forsøk, blir han ansett mislykket arbeid og Laravel setter den inn i tabellen failed_jobs (eller i DynamoDB hvis du konfigurerer det på den måten). Tabellen lagrer UUID, tilkobling, kø, jobbnyttelast og unntaket som ble kastet.
Nyttige kommandoer:
php artisan queue:failedå liste opp de mislykkede.php artisan queue:retry <id|all>å prøve dem igjen.php artisan queue:forget <id>å slette én.php artisan queue:flushfor å slette alle (med alternativ for timer i nyere versjoner).php artisan queue:prune-failed --hours=48for å automatisk slette gamle poster.
I Jobber kan du definere en metode failed(Throwable $exception) For ekstra opprydding: varsle brukeren, tilbakestill delvise handlinger, skriv spesialiserte logger osv. Merk at en ny instans av jobben opprettes for å kalle failed()Stol derfor ikke på endringer i eiendommen som er gjort i handle().
Jobbgruppering: grupper av jobber og kombinasjon av dem med strenger
Når du trenger å starte hundrevis eller tusenvis av relaterte jobber (for eksempel importere en gigantisk CSV i deler, behandle filer i grupper, rense data osv.), anbefales det å bruke Laravels batch- funksjonalitet .
Grunnleggende flyt:
- lage tabellen
job_batchesmedphp artisan queue:batches-table && php artisan migrate. - Merk jobbene som skal være en del av grupper med egenskapen
Batchable. - bruk
Bus::batch()å sende et sett med jobber, med tilbakeringingerthen,catchyfinally. - Få tilgang til batchen fra hver jobb med
$this->batch()og sjekk om den er kansellert. - Mulighet for å legge til flere jobber i en pågående gruppe med
$this->batch()->add().
Grupper integreres utmerket med kjeder : du kan ha kjeder i en gruppe eller grupper som elementer i en større kjede. Dette er spesielt nyttig når du vil at flere kjeder skal kjøre "parallelt" og utløse noe når de alle er fullført.
Arbeidstakers utførelse, prioriteringer og utplassering
All magien med køer skjer fordi du har en eller flere arbeidere kjører kommandoen queue:work (o queue:listen(selv om sistnevnte er mindre effektiv). Disse prosessene er langvarige daemoner som lytter til sine respektive køer.
Viktige alternativer for queue:work:
- Tilkobling:
php artisan queue:work redis,queue:work databaseOsv - Colas:
--queue=high,default,lowå prioritere. - -elleve: behandler én enkelt jobb og avslutter.
- –maks-jobberbehandler X jobber og avslutter (for å starte arbeidere på nytt med jevne mellomrom og frigjøre minne).
- –maks-tid: behandles i N sekunder og avsluttes deretter.
- -sovesekunder med venting når ingen jobber er tilgjengelige.
- –stopp-når-tom: tømmer køen og lukkes plettfritt (ideelt i Docker-miljøer eller engangsjobber).
- – timeoutsekunder med tidsavbrudd per jobb, som vi nevnte tidligere.
- -makt: for å behandle jobber selv om appen er i vedlikeholdsmodus.
Fordi disse prosessene kjører lenge, brukes nesten alltid en prosessmonitor som Supervisor (på Linux) i produksjon til å starte X-arbeidere, starte dem på nytt hvis de krasjer, og administrere logger. En typisk Supervisor-konfigurasjonsblokk for Laravel definerer:
- kommando med
php artisan queue:work ...betong. - numprocs for å angi hvor mange arbeidere som skal lanseres parallelt.
- Loggstier, bruker, automatiske omstarter osv.
Pause og gjenoppta køer i Laravel
La oss komme til det som ofte er viktig i vedlikehold: hvordan man kan sette arbeidere i kø på pause uten å stoppe dem brått og uten å la jobber være uferdige. Laravel tilbyr flere mekanismer, noen nyere, noen klassiske, for å kontrollere dette.
Pause: kø:pause og avbruddssignaler
I nyere versjoner legger Laravel til spesifikke kommandoer for å sette arbeidere på pause og gjenoppta utførelsen :
php artisan queue:pause: forteller systemet at det skal slutte å ta nye jobber, men la de som allerede er i gang bli ferdige.php artisan queue:continue: gjenopptar behandlingen av nye jobber der den slapp.
Disse kommandoene fungerer ved å sende signaler til arbeiderne gjennom mellomlagringsmekanismen som Laravel bruker internt. Derfor er det viktig å ha en riktig konfigurert mellomlagringsdriver (memcached, redis, database, file osv.) selv om den faktiske mellomlagringskøen din er noe annet.
Viktig: Å sette en kø eller arbeider på pause avbryter eller sletter ikke jobber som allerede er i køen . Det forhindrer bare at flere jobber fjernes fra køen mens pausen varer.
Undersøkelse av forstyrrelser og innvirkning på ytelse
Hver gang en arbeider fullfører en jobb, sjekker Laravel hurtigbufferen for omstarts-, pause- eller fortsettelsessignaler . Dette har en ubetydelig kostnad, men den eksisterer. Hvis du er ekstremt fokusert på ytelse og vet at du ikke trenger å sette arbeidere på pause eller starte dem på nytt fra kommandoer, kan du deaktivere denne avstemningen ved å kalle:
Queue::withoutInterruptionPolling();
Eller til og med justere statiske egenskaper til Illuminate\Queue\Worker for å deaktivere spesifikke berøringer ($kan startes på nytt, $pausbarMen hvis du gjør dette og deretter prøver å bruke queue:pause o queue:restartarbeiderne De vil ikke finne ut av detDet er en designbeslutning som bør vurderes nøye.
Pause manuelt med Supervisor eller Docker
I tillegg til Laravels egne kommandoer , blir prosesser ofte "pauset" indirekte i produksjonsmiljøer:
- Stoppe programmet i Supervisor (
supervisorctl stop laravel-worker:*), som dreper eller stopper arbeiderne. - hjelp –stopp-når-tom i utplasseringer for å la arbeiderne fullføre det som er i køen og deretter stenge ned.
- I Docker, la containeren behandles med
--stop-when-emptyog så slår den seg av.
Forskjellen med queue:pause Ved å stoppe prosessene helt, stopper du behandlingen av jobber inntil arbeiderne starter på nytt. intern pause Du kan lagre prosessene i minnet og vente på kommandoen continueDette er nyttig for rask tilbakerulling av distribusjoner eller korte vedlikeholdsperioder.
Databasetransaksjoner og after_commit
En klassisk feil: å sende jobber innenfor databasetransaksjoner . Hvis du ikke er forsiktig, kan arbeideren utføre jobben før commit-en er gjort, og modellen eller dataene du forventer er kanskje ikke i databasen ennå.
For å unngå denne dansen har du to alternativer:
- Aktiver
'after_commit' => truei konfigurasjonen av køtilkoblingen. Dermed blir enhver jobb som sendes i en transaksjon utsatt internt til den er bekreftet. - Bruk metoder per jobb
afterCommit()obeforeCommit()ved utsending, for å tvinge frem oppførselen bare i spesifikke jobber.
Hvis transaksjonen reverseres, forkastes jobbene som ble sendt underveis uten å havne i køen, noe som vanligvis er ønskelig for å opprettholde konsistens.
Overvåking, kørydding og testing
Når du først har fått køene oppe og går for alvor, er det ikke nok å bare kaste ut jobber og glemme det; du bør overvåke og teste hvordan alt oppfører seg.
Nyttige verktøy og kommandoer:
queue:clearfor å tømme en bestemt kø (SQS, Redis, database).queue:monitorå overvåke antall jobber i bestemte køer og utløse hendelsenQueueBusyhvis de overskrider en terskel.- Jobbarrangementer som
Queue::before,Queue::after,Queue::loopingyQueue::failingå koble til tilpasset logikk (logger, beregninger, tilbakestillinger osv.). - Forfalskninger i testing hjelp
Queue::fake()yBus::fake()for å bekrefte at jobber, strenger eller batcher har blitt sendt uten at de faktisk ble utført.
I tester kan du si ting som «denne jobben har blitt satt i kø X ganger» , «en kjede med disse jobbene har blitt sendt i denne rekkefølgen» eller «ingen bestemt jobb har blitt satt i kø», noe som gir mye sikkerhet i komplekse flyter.
Med hele dette økosystemet – drivere som Redis eller SQS, godt utformede jobber, mellomvare for finjustering, batcher, kjeder, konfigurasjon av nye forsøk, veilederstyrte arbeidere og kommandoer som queue:pause y queue:continue– Laravel lar deg mestre bakgrunnsprosessering ned til millimeteren, fra typisk e-postsending til distribuerte køarkitekturer med failover, slik at applikasjonen din fortsetter å reagere raskt på HTTP-laget mens tungt arbeid gjøres under uten å blokkere brukeren.