- Laravel tilbyder en samlet kø-API med flere drivere (database, Redis, SQS…) og adskillelse mellem forbindelser og logiske køer.
- Job gør det muligt at flytte tunge opgaver til baggrunden, med understøttelse af serialisering af modeller, middleware, engangsjob, kryptering, batches og strenge.
- Medarbejdere administreres med queue:work, Supervisor og kommandoer som queue:pause/queue:continue, der styrer genforsøg, timeouts og prioriteter.
- Der findes et komplet økosystem til fejl, overvågning og testning (failed_jobs, queue:retry, queue:monitor, Queue::fake), der gør køer pålidelige i produktion.
At arbejde med køer i Laravel er næsten obligatorisk i ethvert halvseriøst projekt: at sende e-mails, behandle CSV-filer, generere PDF'er, ændre størrelsen på billeder, kalde eksterne API'er ... Hvis alt dette gøres i den primære HTTP-anmodning, bliver webstedet langsomt, der vises 500 fejl, og brugeren ender desperat med at stirre på en tom skærm.
Den gode nyhed er, at Laravel tilbyder en kraftfuld og fleksibel køinfrastruktur , der giver dig mulighed for at delegere tunge opgaver til baggrundsprocesser, administrere dem efter prioritet, gruppere dem i batches, overvåge dem, gentage dem, når de fejler, og endda midlertidigt sætte arbejdere på pause til vedligeholdelse. Lad os se nærmere på (og ikke udelade noget) hvordan du får mest muligt ud af det, herunder hvordan du sætter det på pause, genoptager og kontrollerer dets adfærd i produktion.
Grundlæggende begreber: forbindelser, køer og drivere
I Laravel skal du forstå forskellen mellem, før du sætter noget på pause køforbindelser og selve køerne. i config/queue.php du har et array connections hvor du definerer hver backend: database, redis, beanstalkd, sqs, synkronisering, nul, failover, rabbitmq (hvis du tilføjer det) osv.
Hver forbindelse kan have flere logiske køer (navne som default, emails, high, low, importsAttributten queue Hver forbindelse angiver, hvilken standardkø job skal placeres i, hvis ingen anden er angivet. onQueue()På denne måde kan du gøre ting som:
- En hurtig kø til e-mails eller korte transaktioner.
- Endnu en lav prioritet til lange opgaver såsom behandling af videoer eller store rapporter.
- Køer segmenteret efter opgavetype:
imports,notificaciones,reportesOsv
Når du starter arbejderen med php artisan queue:workSom standard lytter den til den kø, der er angivet som Standard på den valgte forbindelse. Hvis du vil prioritere, kan du sende flere kommaseparerede køer:
php artisan queue:work redis --queue=high,default,low
På denne måde behandler arbejderen high først , derefter default , og først derefter low , hvilket er afgørende, når systemet er belastet, og du ikke ønsker, at en 30-minutters rapport skal blokere e-mails med høj prioritet.
Kødrivere og forudsætninger
Laravel tilbyder en samlet API til flere kødrivere , men hver har sine egne specifikke funktioner og afhængigheder. Det er afgørende at vælge den rigtige driver, før man diskuterer at sætte arbejdere på pause.
Chaufførdatabase
Føreren database Den gemmer jobbene i en SQL-tabel (normalt jobsDet er nemt at sætte op og perfekt til små projekter eller udviklingsmiljøer, hvor du ikke vil rode rundt med Redis eller SQS.
Grundlæggende trin:
- Generer migreringen:
php artisan queue:table(eller i nyere versioner kommer det somcreate_jobs_tableStandard). - Kør migreringer:
php artisan migrate. - konfigurering KØFORBINDELSE=database i
.envog bekræft iconfig/queue.phpat'default' => env('QUEUE_CONNECTION','database').
Det er praktisk og robust nok, men med mange køer og meget trafik kan det blive en flaskehals , da alt går gennem den samme relationelle database.
Chauffør Redis
Redis -driveren er standardarbejdshesten i produktion. Den er hurtig, understøtter avancerede funktioner (låsning, hastighedsbegrænsning, atomlåse, Horizon osv.) og skalerer rigtig godt.
Vigtige punkter:
- Du skal konfigurere Redis-forbindelsen i
config/database.php. - Indstillingerne
serializerycompressionfra Redis De er ikke kompatible med køchaufføren. - Hvis du bruger Redis-klyngeNavnene på køerne skal have et hashtag, for eksempel
{default}så alle nøglerne i køen falder på samme plads. - Valget
block_forDet giver arbejderen mulighed for at blokere, mens de venter på job i et par sekunder, i stedet for kontinuerligt at afstemme: sparer CPU og reducerer forespørgsler til Redis-serveren.
For eksempel:
'redis' => ,
Hvis du sætter blok_for = 0Medarbejderen forbliver blokeret på ubestemt tid, indtil et job bliver ledigt. Dette er vigtigt at huske på, hvis du ønsker, at den skal reagere hurtigt på signaler som f. SIGTERM eller sætte kommandoer på pause.
Andre drivere: SQS, Beanstalkd, null, failover…
Udover databaser og redis understøtter Laravel andre systemer :
- Amazon SQSAdministrerede køer på AWS, med understøttelse af FIFOMeddelelsesgrupper, deduplikering og avancerede synlighedsindstillinger. Kræver SDK'et.
aws/aws-sdk-php. - BønnestængelMeget hurtigt og nemt, ved at bruge pakken
pda/pheanstalk. - synkronisere: udfører opgaverne inmediatamente i samme proces. Nyttig i udvikling eller test, men i produktion er det praktisk talt som slet ikke at bruge køer.
- nullKasserer job, så snart de er "afsendt". Bruges til helt at deaktivere køsystemet.
- failoverDette giver dig mulighed for at konfigurere flere forbindelser, og hvis den primære fejler, forsøger Laravel at pushe jobbet til den næste på listen. Perfekt til miljøer, hvor høj tilgængelighed er kritisk.
På niveauet for at sætte arbejdere på pause og genoptage dem, er logikken praktisk talt den samme uanset driveren, fordi den administreres fra Artisan-kommandoerne og Worker -klassen , ikke fra køens backend.
Joboprettelse og modelserialisering
Un Job I Laravel er det simpelthen en klasse, der indkapsler en opgave, der skal udføres i en kø. Den genereres typisk med Artisan og gemmes i app/Jobs.
Sådan opretter du en:
php artisan make:job ProcessPodcast
Den genererede klasse redskaber ShouldQueue og bruger normalt træk Dispatchable, InteractsWithQueue, Queueable y SerializesModelsHjertet ligger i metoden handle()hvilket er hvad arbejderen gør, når jobbet ankommer.
En særlig kraftfuld funktion er den automatiske serialisering af Eloquent-modeller . Hvis du accepterer en model i Job-konstruktøren, tilføjer Laravel ikke hele objektet til køen, kun dets identifikator. Når jobbet behandles, rekonstruerer det modellen fra databasen med dens relationer indlæst.
Typisk eksempel (i pseudokode, for at undgå at gentage det ordret):
- Bygherre modtager Podcast $podcast.
- Trækket
SerializesModelsDen er ansvarlig for at gemme ID'et. - En
handle(AudioProcessor $processor)Du udfører det hårde arbejde (f.eks. lydbehandling).
Hvis du ikke ønsker, at relationerne i en model skal serialiseres (så nyttelasten ikke er enorm), kan du bruge $model->withoutRelations() eller i PHP 8 attributten # på bygherrens fremlagte ejendom.
Afhængighedsinjektion i handle-metoden
En anden fordel er, at du kan injicér tjenester direkte i håndtagsmetoden (som om det var en controller), fordi Laravel også bruger servicecontaineren i Jobs. For eksempel kan du anmode om en AudioProcessorHTTP-klienter, repositories osv., og frameworket tager sig af at løse dem.
Hvis du har brug for ultrafin kontrol over det, der kaldes handledu kan bruge Container::bindMethod() hos en tjenesteudbyder og selv definere injektionslogikken, men i de fleste tilfælde er der ingen grund til at komplicere tingene så meget.
Job Middleware
Ligesom ruter har middleware, kan job også have specifik middleware der kører før og efter jobbet. Dette reducerer gentagen kode i metoderne betydeligt handle() og det er især nyttigt til:
- Hastighedsbegrænsning med Redis.
- undgå overlapper af værker, der berører den samme ressource.
- Regelmæssige undtagelser for ustabile API'er.
- Springe job over under visse betingelser (
Skipmellemvare).
Middleware placeres normalt i app/Jobs/Middleware og returneres fra metoden middleware() Fra Job. Konceptuelt eksempel:
public function middleware(): array { return ;
Særlige jobtyper: unikke, krypterede og låste
Laravel giver dig mulighed for at markere bestemte job som unik for at sikre, at ingen to identiske instanser nogensinde sættes i kø på samme tid. Dette opnås ved at implementere grænsefladen ShouldBeUnique o ShouldBeUniqueUntilProcessingog understøtter definition af en nøgle uniqueId() og en tid uniqueFor.
Dette er ideelt til ting som:
- Genberegn et produkts søgeindeks: kun én gang pr. produkt indtil det er slut.
- Synkroniseringer med eksterne tjenester, der ikke tillader samtidige anmodninger om den samme ressource.
Nedenunder bruger Laravel en atomlås af cache (Redis, memcached, database osv.). Du kan også vælge cachedriveren til den pågældende lås med uniqueVia().
Derudover er der grænsefladen ShouldBeEncrypted, hvormed du angiver, at det komplette job er Indtast din kode, før du går ind i køenMeget nyttigt, når følsomme data skal overføres, og du ikke ønsker, at de skal sendes som almindelig tekst gennem Redis, SQS eller databasen.
Send, forsink og udfør job i forskellige tilstande
Når dit job er defineret, starter du det med Job::dispatch() fra controllere, eventlistenere, Artisan-kommandoer eller endda lukninger. De parametre, du sender til dispatch De går direkte til bygmesteren af Job.
Interessante variationer:
dispatchIf()ydispatchUnless()at konditionere forsendelsen i en enkelt linje.delay()således at jobbet ikke kan behandles før en bestemt dato/tidspunkt.dispatchAfterResponse()oafterResponse()endispatch()Lukninger, som udsætter udførelsen indtil HTTP-svaret er sendt, men inden for den samme PHP-proces.dispatchSync()at køre jobbet synkront (uden at gå gennem køen), men genbruge den samme klasse.- Særlige forbindelser som f.eks.
deferredobackgroundat udføre efter svaret, i den samme proces eller i en ny PHP-proces.
Endelig kan du angive forbindelse og kø med kædede metoder. onConnection() y onQueue(), enten ved afsendelse eller i jobbyggeren.
Finkontrol: genforsøg, backoff, timeouts og fejlhåndtering
En stor del af at arbejde med køer i Laravel er at beslutte, hvor mange gange man skal forsøge et job igen , hvor længe man skal vente mellem forsøg, og hvornår man skal betragte det som en fiasko.
Tilgængelige meninger:
--triesenqueue:workat indstille det maksimale antal forsøg for alle job for den pågældende arbejder (medmindre jobbet definerer sit eget)$triesotries()).$trieseller en metodetries()i jobklassen til kontrol pr. job.retryUntil()at sige: "prøv igen, som du ønsker, indtil denne gang, derefter, fiasko." Hvis det falder sammen medtries, kommandoretryUntil.$maxExceptionsat afbryde, når problemet skyldes gentagne uhåndterede undtagelser.$timeouto--timeoutfor at angive, hvor mange sekunder et job kan køre, før arbejderen afslutter den underordnede proces.$failOnTimeoutfor at markere jobbet som mislykket i tilfælde af timeout.$backoffmetodenbackoff()at definere, hvor længe der skal ventes mellem forsøg, selv med eksponentielle værdier.
Hvis et job kaster en uopdaget undtagelse, vil Laravel... slipper tilbage i halen indtil de konfigurerede forsøg er opbrugt. Du kan styre dette manuelt med release($segundos) o fail($exception) når du bevidst vil markere et job som mislykket.
Mislykkede job, tabel med failed_jobs og beskæring
Når et job udtømmer hans forsøg, bliver han betragtet som mislykket arbejde og Laravel indsætter det i tabellen failed_jobs (eller i DynamoDB, hvis du konfigurerer det på den måde). Den tabel gemmer UUID, forbindelse, kø, jobdata og den undtagelse, der blev kastet.
Nyttige kommandoer:
php artisan queue:failedat liste de mislykkede.php artisan queue:retry <id|all>at prøve dem igen.php artisan queue:forget <id>at slette én.php artisan queue:flushfor at slette alle (med mulighed for timer i nyere versioner).php artisan queue:prune-failed --hours=48til automatisk at slette gamle poster.
I Jobs kan du definere en metode failed(Throwable $exception) For ekstra oprydning: underret brugeren, fortryd delvise handlinger, skriv specialiserede logfiler osv. Bemærk, at en ny instans af jobbet oprettes for at kalde failed()Stol derfor ikke på ændringer i ejendommen, der er foretaget i handle().
Jobbatching: jobbatcher og kombination af dem med strenge
Når du har brug for at starte hundredvis eller tusindvis af relaterede job (f.eks. import af en kæmpe CSV-fil i chunks, behandling af filer i batches, rensning af data osv.), anbefales det at bruge Laravels batch- funktionalitet .
Grundlæggende flow:
- oprette bordet
job_batchesmedphp artisan queue:batches-table && php artisan migrate. - Markér de job, der skal være en del af batches, med egenskaben
Batchable. - Brug
Bus::batch()at sende et sæt job med tilbagekaldthen,catchyfinally. - Få adgang til batchen fra hvert job med
$this->batch()og tjek om den er aflyst. - Mulighed for at tilføje flere job til en igangværende batch med
$this->batch()->add().
Batches integreres smukt med kæder : du kan have kæder inden for en batch eller batches som elementer i en større kæde. Dette er især nyttigt, når du vil have flere kæder til at køre "parallelt" og udløse noget, når de alle er færdige.
Medarbejderudførelse, prioriteter og implementering
Al magien ved køer opstår, fordi du har en eller flere arbejdere kører kommandoen queue:work (o queue:listen(selvom sidstnævnte er mindre effektiv). Disse processer er langvarige dæmoner, der lytter til deres respektive køer.
Nøglemuligheder for queue:work:
- Tilslutning:
php artisan queue:work redis,queue:work databaseOsv - Colas:
--queue=high,default,lowat prioritere. - -elleve: behandler et enkelt job og afslutter.
- –max-jobsbehandler X job og afslutter (for periodisk at genstarte arbejdere og frigøre hukommelse).
- –maks-tid: behandles i N sekunder og afsluttes derefter.
- -sovesekunders ventetid, når der ikke er ledige job.
- –stop-når-tom: tømmer køen og lukker pænt (ideelt i Docker-miljøer eller enkeltstående job).
- –timeoutsekunders timeout pr. job, som vi nævnte før.
- -kraft: for at behandle job, selvom appen er i vedligeholdelsestilstand.
Da disse processer er langvarige, bruges en procesmonitor som Supervisor (på Linux) i produktionen næsten altid til at starte X-workere, genstarte dem, hvis de går ned, og administrere logfiler. En typisk Supervisor-konfigurationsblok til Laravel definerer:
- kommando med
php artisan queue:work ...beton. - numprocs for at angive, hvor mange arbejdere der skal lanceres parallelt.
- Logstier, bruger, automatiske genstarter osv.
Pause og genoptagelse af køer i Laravel
Lad os komme til det, der ofte er vigtigt i forbindelse med vedligeholdelse: hvordan man sætter medarbejdere i køen på pause uden at stoppe dem pludselig og uden at lade job stå ufærdige. Laravel tilbyder adskillige mekanismer, nogle nyere, nogle klassiske, til at styre dette.
Pause: kø:pause og afbrydelsessignaler
I nyere versioner tilføjer Laravel specifikke kommandoer til at sætte arbejdere på pause og genoptage udførelsen :
php artisan queue:pause: fortæller systemet, at det skal stoppe med at tage nye job, men lade dem, der allerede er i gang, blive færdige.php artisan queue:continuegenoptager behandlingen af nye job, hvor det slap.
Disse kommandoer fungerer ved at sende signaler til workers via den caching-mekanisme, som Laravel bruger internt. Derfor er det vigtigt at have en korrekt konfigureret cache-driver (memcached, redis, database, file osv.), selvom din faktiske cache-kø er noget andet.
Vigtigt: At sætte en kø eller en arbejder på pause annullerer eller sletter ikke job, der allerede er i kø ; det forhindrer blot, at flere job fjernes fra køen, mens pausen varer.
Afstemning af forstyrrelser og deres indflydelse på præstationen
Hver gang en worker afslutter et job, tjekker Laravel cachen for genstarts-, pause- eller fortsættelsessignaler . Dette har en ubetydelig omkostning, men den eksisterer. Hvis du er ekstremt fokuseret på ydeevne og ved, at du ikke behøver at sætte workers på pause eller genstarte dem fra kommandoer, kan du deaktivere denne polling ved at kalde:
Queue::withoutInterruptionPolling();
Eller endda justere statiske egenskaber for Illuminate\Queue\Worker for at deaktivere specifikke berøringer ($genstartbar, $pausebarMen hvis du gør dette og derefter prøver at bruge queue:pause o queue:restartarbejderne De finder ikke ud af detDet er en designbeslutning, der bør overvejes nøje.
Sæt manuelt på pause med Supervisor eller Docker
Udover Laravels egne kommandoer bliver processer i produktionsmiljøer ofte indirekte "sat på pause":
- Stop af programmet i Supervisor (
supervisorctl stop laravel-worker:*), som dræber eller stopper arbejderne. - ved hjælp af –stop-når-tom i implementeringer for at lade arbejderne afslutte det, der er i køen, og derefter lukke ned.
- I Docker, lader man containeren behandle med
--stop-when-emptyog så slukker den.
Forskellen med queue:pause Ved at stoppe processerne helt, stopper du behandlingen af job, indtil arbejderne genstarter. intern pause Du kan gemme processerne i hukommelsen og vente på kommandoen continueDette er nyttigt til hurtige rollback-implementeringer eller korte vedligeholdelsesperioder.
Databasetransaktioner og after_commit
En klassisk fejl: at afsende job inden for databasetransaktioner . Hvis du ikke er forsigtig, kan arbejderen udføre jobbet, før commit'en er foretaget, og den model eller de data, du forventer , er muligvis endnu ikke i databasen.
For at undgå denne dans har du to muligheder:
- Aktiver
'after_commit' => truei køforbindelseskonfigurationen. Således udskydes ethvert job, der sendes i en transaktion, internt, indtil det er bekræftet. - Brug metoder pr. job
afterCommit()obeforeCommit()ved afsendelse, for kun at gennemtvinge adfærden i bestemte job.
Hvis transaktionen tilbageføres, kasseres de job, der blev afsendt under den , uden nogensinde at blive placeret i køen, hvilket er præcis, hvad der normalt ønskes for at opretholde konsistens.
Overvågning, kørensning og testning
Når du først har køerne oppe at køre for alvor, er det ikke nok bare at smide job ud og glemme alt om det; du bør overvåge og teste, hvordan alting opfører sig.
Nyttige værktøjer og kommandoer:
queue:clearat tømme en specifik kø (SQS, Redis, database).queue:monitorat overvåge antallet af job i bestemte køer og udløse hændelsenQueueBusyhvis de overstiger en tærskel.- Jobbegivenheder som
Queue::before,Queue::after,Queue::loopingyQueue::failingat koble brugerdefineret logik (logfiler, metrikker, rollbacks osv.). - Forfalskninger i test hjælp
Queue::fake()yBus::fake()for at verificere, at job, strenge eller batches er blevet afsendt uden rent faktisk at udføre dem.
I tests kan du angive ting som "dette job er blevet sat i kø X gange" , "en kæde med disse job er blevet afsendt i denne rækkefølge" eller "intet bestemt job er blevet sat i kø", hvilket giver en masse sikkerhed i komplekse flows.
Med hele dette økosystem – drivere som Redis eller SQS, veldesignede job, middleware til finjustering, batches, kæder, konfiguration af nye forsøg, supervisor-administrerede arbejdere og kommandoer som queue:pause y queue:continue— Laravel giver dig mulighed for at mestre baggrundsbehandling ned til millimeteren, fra typisk e-mailafsendelse til distribuerede køarkitekturer med failover, hvilket sikrer, at din applikation fortsat reagerer hurtigt på HTTP-laget, mens der udføres tungt arbejde nedenunder uden at blokere brugeren.