- Laravel erbjuder ett enhetligt kö-API med flera drivrutiner (databas, Redis, SQS…) och separation mellan anslutningar och logiska köer.
- Jobb gör det möjligt att flytta tunga uppgifter till bakgrunden, med stöd för serialisering av modeller, mellanprogramvara, engångsjobb, kryptering, batchar och strängar.
- Arbetare hanteras med queue:work, Supervisor och kommandon som queue:pause/queue:continue, vilket styr återförsök, timeouts och prioriteringar.
- Det finns ett komplett ekosystem för fel, övervakning och testning (failed_jobs, queue:retry, queue:monitor, Queue::fake) som gör köer tillförlitliga i produktion.
Att arbeta med köer i Laravel är nästan obligatoriskt i alla halvseriösa projekt: skicka e-postmeddelanden, bearbeta CSV-filer, generera PDF-filer, ändra storlek på bilder, anropa externa API:er… Om allt detta görs i den huvudsakliga HTTP-förfrågan blir webbplatsen långsam, 500 fel visas och användaren stirrar desperat på en tom skärm.
Den goda nyheten är att Laravel erbjuder en kraftfull och flexibel köinfrastruktur som låter dig delegera tunga uppgifter till bakgrundsprocesser, hantera dem efter prioritet, gruppera dem i batcher, övervaka dem, försöka igen när de misslyckas och till och med tillfälligt pausa arbetare för underhåll. Låt oss titta närmare (och inte utelämna något) på hur du får ut det mesta av det, inklusive hur du pausar, återupptar och kontrollerar dess beteende i produktion.
Grundläggande begrepp: anslutningar, köer och drivrutiner
I Laravel, innan du pausar något, måste du förstå skillnaden mellan köförbindelser och själva köerna. I config/queue.php du har en array connections där du definierar varje backend: databas, redis, beanstalkd, sqs, synkronisering, null, redundansväxling, rabbitmq (om du lägger till det) etc.
Varje anslutning kan ha flera logiska köer (namn som default, emails, high, low, importsAttributet queue Varje anslutning anger vilken standardkö som jobb hamnar i om ingen annan anges. onQueue()På så sätt kan du göra saker som:
- En snabb kö för e-postmeddelanden eller korta transaktioner.
- En annan låg prioritet för långa uppgifter som att bearbeta videor eller stora rapporter.
- Köer segmenterade efter uppgiftstyp:
imports,notificaciones,reportesEtc.
När du startar arbetaren med php artisan queue:workSom standard lyssnar den på den kö som anges som standard på den valda anslutningen. Om du vill prioritera kan du skicka flera kommaseparerade köer:
php artisan queue:work redis --queue=high,default,low
På så sätt bearbetar arbetaren först high , sedan default och först sedan low , vilket är avgörande när systemet är belastat och du inte vill att en 30-minutersrapport ska blockera e-postmeddelanden med hög prioritet.
Ködrivrutiner och förutsättningar
Laravel erbjuder ett enhetligt API för flera ködrivrutiner , men var och en har sina egna specifika funktioner och beroenden. Att välja rätt drivrutin är avgörande innan man diskuterar pausning av arbetare.
Förardatabas
Föraren databas Den lagrar jobben i en SQL-tabell (vanligtvis jobsDet är enkelt att installera och perfekt för små projekt eller utvecklingsmiljöer där du inte vill krångla med Redis eller SQS.
Grundläggande steg:
- Generera migreringen:
php artisan queue:table(eller i nyare versioner kommer det somcreate_jobs_tableav defekto). - Kör migreringar:
php artisan migrate. - konfigurering QUEUE_CONNECTION=databas i
.envoch bekräfta iconfig/queue.phpque'default' => env('QUEUE_CONNECTION','database').
Det är bekvämt och robust nog, men med många köer och mycket trafik kan det bli en flaskhals , eftersom allt går igenom samma relationsdatabas.
Förare Redis
Redis -drivrutinen är standardarbetshästen i produktion. Den är snabb, har stöd för avancerade funktioner (låsning, hastighetsbegränsning, atomlås, Horizon, etc.) och skalar mycket bra.
Viktiga punkter:
- Du måste konfigurera Redis-anslutningen i
config/database.php. - Alternativen
serializerycompressionfrån Redis De är inte kompatibla med köföraren. - Om du använder Redis-klusterNamnen på köerna måste ha en hashtagg, till exempel
{default}så att alla nycklar i den kön hamnar på samma plats. - Alternativet
block_forDet gör att arbetaren kan blockera medan de väntar på jobb i några sekunder, istället för att kontinuerligt polla: sparar CPU och minskar antalet frågor till Redis-servern.
Till exempel:
'redis' => ,
Om du lägger block_for = 0Arbetaren förblir blockerad på obestämd tid tills ett jobb blir ledigt, något att tänka på om du vill att den ska reagera snabbt på signaler som SIGTERM eller pausa kommandon.
Andra drivrutiner: SQS, Beanstalkd, null, redundansväxling…
Förutom databaser och Redis stöder Laravel andra system :
- Amazon SQSHanterade köer på AWS, med stöd för FIFOMeddelandegrupper, deduplicering och avancerade synlighetsinställningar. Kräver SDK.
aws/aws-sdk-php. - BönstjälkVäldigt snabbt och enkelt att använda paketet
pda/pheanstalk. - synkroniserautför uppgifterna omedelbart i samma process. Användbart vid utveckling eller testning, men i produktion är det praktiskt taget som att inte använda köer alls.
- null: Ignorerar jobb så snart de är "skickade". Används för att helt inaktivera kösystemet.
- failoverDetta låter dig konfigurera flera anslutningar, och om den primära misslyckas försöker Laravel skicka jobbet till nästa i listan. Perfekt för miljöer där hög tillgänglighet är kritisk.
När det gäller att pausa och återuppta arbetare är logiken praktiskt taget densamma oavsett drivrutin, eftersom den hanteras från Artisan-kommandona och Worker- klassen , inte från kö-backend.
Jobbskapande och modellserialisering
Un Jobb I Laravel är det helt enkelt en klass som inkapslar en uppgift som ska köras i en kö. Den genereras vanligtvis med Artisan och sparas i app/Jobs.
Så här skapar du en:
php artisan make:job ProcessPodcast
Den genererade klassen redskap ShouldQueue och använder vanligtvis egenskaper Dispatchable, InteractsWithQueue, Queueable y SerializesModelsHjärtat ligger i metoden handle()vilket är vad arbetaren gör när jobbet anländer.
En särskilt kraftfull funktion är den automatiska serialiseringen av Eloquent-modeller . Om du accepterar en modell i jobbkonstruktorn lägger Laravel inte till hela objektet i kön, bara dess identifierare. När jobbet bearbetas rekonstruerar det modellen från databasen med dess relationer inlästa.
Typiskt exempel (i pseudokod, för att undvika att upprepa det ordagrant):
- Byggaren får Podcast $podcast.
- Egenskapen
SerializesModelsDen ansvarar för att spara ID:t. - En
handle(AudioProcessor $processor)Du gör det hårda arbetet (till exempel bearbetar ljud).
Om du inte vill att relationerna i en modell ska serialiseras (så att nyttolasten inte blir enorm) kan du använda $model->withoutRelations() eller i PHP 8 attributet # på den fastighet som byggherren marknadsför.
Beroendeinjektion i handle-metoden
En annan fördel är att du kan injicera tjänster direkt i handle-metoden (som om det vore en kontroller), eftersom Laravel också använder servicecontainern i Jobs. Till exempel kan du begära en AudioProcessorHTTP-klienter, repositories etc., och ramverket tar hand om att lösa dem.
Om du behöver ultrafin kontroll över det som kallas handledu kan använda Container::bindMethod() hos en tjänsteleverantör och definiera injektionslogiken själv, men i de flesta fall finns det ingen anledning att komplicera saker så mycket.
Jobb-mellanprogramvara
Precis som rutter har mellanprogramvara kan även jobb ha specifik mellanprogramvara som körs före och efter jobbet. Detta minskar repetitiv kod i metoderna avsevärt handle() och det är särskilt användbart för:
- Hastighetsbegränsning med Redis.
- undvika överlappar av verk som berör samma resurs.
- Regelbundna undantag för instabila API:er.
- Hoppa över jobb under vissa villkor (
Skipmellanprogramvara).
Mellanprogramvara placeras vanligtvis i app/Jobs/Middleware och returneras från metoden middleware() Från Job. Konceptuellt exempel:
public function middleware(): array { return ;
Speciella typer av jobb: unika, krypterade och låsta
Laravel låter dig markera vissa jobb som unik för att säkerställa att inga två identiska instanser någonsin köas samtidigt. Detta uppnås genom att implementera gränssnittet ShouldBeUnique o ShouldBeUniqueUntilProcessingoch stöder definitionen av en nyckel uniqueId() och en tid uniqueFor.
Detta är idealiskt för saker som:
- Beräkna om en produkts sökindex: endast en gång per produkt tills den är klar.
- Synkroniseringar med externa tjänster som inte tillåter samtidiga begäranden för samma resurs.
Nedan använder Laravel en atomlås av cache (Redis, memcached, databas, etc.). Du kan också välja cachedrivrutinen för det låset med uniqueVia().
Dessutom finns gränssnittet ShouldBeEncrypted, med vilket du anger att det kompletta jobbet är Ange din kod innan du går in i könMycket användbart när man skickar känslig data och man inte vill att den ska skickas i klartext genom Redis, SQS eller databasen.
Skicka, fördröja och kör jobb i olika lägen
När ditt jobb är definierat startar du det med Job::dispatch() från kontroller, händelselyssnare, Artisan-kommandon eller till och med stängningar. Parametrarna du skickar till dispatch De går direkt till den som byggde Job.
Intressanta variationer:
dispatchIf()ydispatchUnless()att konditionera försändelsen i en enda rad.delay()så att jobbet inte kan bearbetas förrän ett visst datum/tid.dispatchAfterResponse()oafterResponse()endispatch()Stängningar, som skjuter upp körningen tills HTTP-svaret har skickats, men inom samma PHP-process.dispatchSync()att köra jobbet synkront (utan att gå igenom kön) men återanvända samma klass.- Speciella kopplingar som t.ex.
deferredobackgroundatt köra efter svaret, i samma process eller i en ny PHP-process.
Slutligen kan du ange anslutning och kö med kedjiga metoder. onConnection() y onQueue(), antingen vid expediering eller i jobbbyggaren.
Finkontroll: återförsök, backoff, timeouts och felhantering
En stor del av att arbeta med köer i Laravel är att bestämma hur många gånger man ska försöka om ett jobb , hur länge man ska vänta mellan försöken och när man ska betrakta det som ett misslyckande.
Tillgängliga synpunkter:
--triesenqueue:workför att ställa in det maximala antalet försök för alla jobb för den arbetaren (såvida inte jobbet definierar sina egna)$triesotries()).$trieseller en metodtries()i jobbklassen för kontroll per jobb.retryUntil()att säga: ”försök igen som du vill tills denna gång, efter det, misslyckande.” Om det sammanfaller medtries, kommandoretryUntil.$maxExceptionsatt avbryta när problemet beror på upprepade ohanterade undantag.$timeouto--timeoutför att ange hur många sekunder ett jobb kan köras innan arbetaren avslutar underprocessen.$failOnTimeoutför att markera jobbet som misslyckat vid timeout.$backoffmetodenbackoff()för att definiera hur länge det ska vänta mellan försök, även med exponentiella värden.
Om ett jobb utlöser ett oupptäckt undantag kommer Laravel att... släpps tillbaka in i svansen tills de konfigurerade försöken är uttömda. Du kan styra detta manuellt med release($segundos) o fail($exception) när du avsiktligt vill markera ett jobb som misslyckat.
Misslyckade jobb, tabellen failed_jobs och beskärning
När ett jobb uttömt hans ansträngningar, börjar han betraktas som misslyckat arbete och Laravel infogar den i tabellen failed_jobs (eller i DynamoDB om du konfigurerar det på det sättet). Den tabellen lagrar UUID, anslutning, kö, jobbnyttolast och det undantag som utlöstes.
Användbara kommandon:
php artisan queue:failedatt lista de misslyckade.php artisan queue:retry <id|all>att prova dem igen.php artisan queue:forget <id>att radera en.php artisan queue:flushför att radera alla (med möjlighet för timmar i nyare versioner).php artisan queue:prune-failed --hours=48för att automatiskt rensa gamla poster.
I Jobs kan du definiera en metod failed(Throwable $exception) För extra rensning: meddela användaren, återställ delåtgärder, skriv specialiserade loggar etc. Observera att en ny instans av jobbet skapas för att anropa failed()Lita därför inte på fastighetsändringar som gjorts i handle().
Jobbbatchning: batchar av jobb och kombination av dem med strängar
När du behöver starta hundratals eller tusentals relaterade jobb (till exempel importera en gigantisk CSV-fil i bitar, bearbeta filer i batcher, rensa data etc.) är det lämpligt att använda Laravels batchfunktion.
Grundflöde:
- skapa tabellen
job_batchesmedphp artisan queue:batches-table && php artisan migrate. - Markera de jobb som ska ingå i batcher med egenskapen
Batchable. - Tillämpa
Bus::batch()att skicka en uppsättning jobb, med återanropthen,catchyfinally. - Åtkomst till batchen från varje jobb med
$this->batch()och kolla om den är avbruten. - Möjlighet att lägga till fler jobb till en pågående batch med
$this->batch()->add().
Batchar integreras utmärkt med kedjor : du kan ha kedjor inom en batch eller batchar som element i en större kedja. Detta är särskilt användbart när du vill att flera kedjor ska köras "parallellt" och utlösa något när de alla har slutförts.
Arbetarens utförande, prioriteringar och utplacering
All magi med köer uppstår eftersom du har en eller flera arbetare kör kommandot queue:work (o queue:listen(även om den senare är mindre effektiv). Dessa processer är långvariga daemoner som lyssnar på sina respektive köer.
Viktiga alternativ för queue:work:
- Anslutning:
php artisan queue:work redis,queue:work databaseEtc. - Colas:
--queue=high,default,lowatt prioritera. - -elva: bearbetar ett enskilt jobb och avslutas.
- –max-jobbbearbetar X jobb och avslutar (för att regelbundet starta om arbetare och frigöra minne).
- –max-tid: bearbetas i N sekunder och avslutas sedan.
- -sovasekunders väntan när inga jobb är tillgängliga.
- –stoppa-när-tom: tömmer kön och stänger utan problem (perfekt i Docker-miljöer eller för engångsjobb).
- – timeoutsekunders timeout per jobb, som vi nämnde tidigare.
- -tvinga: för att bearbeta jobb även om appen är i underhållsläge.
Eftersom dessa processer är långvariga används nästan alltid en processövervakare som Supervisor (på Linux) i produktion för att starta X-arbetare, starta om dem om de kraschar och hantera loggar. Ett typiskt Supervisor-konfigurationsblock för Laravel definierar:
- kommando med
php artisan queue:work ...betong. - numprocs för att ange hur många arbetare som ska lanseras parallellt.
- Loggsökvägar, användare, automatiska omstarter etc.
Pausa och återuppta köer i Laravel
Låt oss gå vidare till det som ofta är viktigt inom underhåll: hur man pausar köarbetare utan att abrupt stoppa dem och utan att lämna jobb oavslutade. Laravel erbjuder flera mekanismer, vissa nyare, vissa klassiska, för att styra detta.
Paus: kö:paus och avbrottssignaler
I senare versioner lägger Laravel till specifika kommandon för att pausa och återuppta körningen av arbetare:
php artisan queue:pause: anger att systemet ska sluta ta nya jobb, men låta de som redan pågår slutföras.php artisan queue:continueåterupptar bearbetningen av nya jobb där den slutade.
Dessa kommandon fungerar genom att skicka signaler till arbetarna via cachningsmekanismen som Laravel använder internt. Det är därför det är viktigt att ha en korrekt konfigurerad cachedrivrutin (memcached, redis, database, file, etc.) även om din faktiska cache-kö är något annat.
Viktigt: Att pausa en kö eller arbetare avbryter eller tar inte bort jobb som redan är i kö ; det förhindrar helt enkelt att fler jobb tas bort från kön medan pausen varar.
Undersökning av störningar och påverkan på prestanda
Varje gång en arbetare avslutar ett jobb kontrollerar Laravel cachen för omstarts-, paus- eller fortsättningssignaler . Detta har en försumbar kostnad, men den existerar. Om du är extremt fokuserad på prestanda och vet att du inte behöver pausa eller starta om arbetare från kommandon kan du inaktivera denna pollning genom att anropa:
Queue::withoutInterruptionPolling();
Eller till och med justera statiska egenskaper för Illuminate\Queue\Worker för att inaktivera specifika beröringar ($omstartbar, $pausbarMen om du gör detta och sedan försöker använda queue:pause o queue:restartarbetarna De kommer inte att få reda på detDet är ett designbeslut som bör övervägas noggrant.
Pausa manuellt med Supervisor eller Docker
Utöver Laravels egna kommandon , i produktionsmiljöer, "pausas" processer ofta indirekt:
- Stoppa programmet i Supervisor (
supervisorctl stop laravel-worker:*), vilket dödar eller stoppar arbetarna. - med användning av –stoppa-när-tom i driftsättningar för att låta arbetarna avsluta det som finns i kön och sedan stänga av.
- I Docker, låta containern bearbetas med
--stop-when-emptyoch sedan stängs den av.
Skillnaden med queue:pause Genom att stoppa processerna helt slutar du bearbeta jobb tills arbetarna startar om. intern paus Du kan spara processerna i minnet och vänta på kommandot continueDetta är användbart för snabba återställningsdistributioner eller korta underhållsperioder.
Databastransaktioner och after_commit
Ett klassiskt misstag: att skicka jobb inom databastransaktioner . Om du inte är försiktig kan arbetaren köra jobbet innan commit görs, och den modell eller data du förväntar dig kanske ännu inte finns i databasen.
För att undvika denna dans har du två alternativ:
- aktivera
'after_commit' => truei könslutningskonfigurationen. Således skjuts alla jobb som skickas inom en transaktion upp internt tills de bekräftas. - Använd metoder per jobb
afterCommit()obeforeCommit()vid dispatch, för att endast tvinga fram beteendet i specifika jobb.
Om transaktionen återförs kasseras de jobb som skickats under den utan att någonsin hamna i kön, vilket är precis vad som vanligtvis är önskvärt för att upprätthålla konsekvens.
Övervakning, köhantering och testning
När du väl har köerna igång på allvar räcker det inte att bara kasta bort jobb och glömma bort det; du bör övervaka och testa hur allt beter sig.
Användbara verktyg och kommandon:
queue:clearför att tömma en specifik kö (SQS, Redis, databas).queue:monitorför att övervaka antalet jobb i vissa köer och utlösa händelsenQueueBusyom de överskrider ett tröskelvärde.- Jobbhändelser som
Queue::before,Queue::after,Queue::loopingyQueue::failingför att koppla anpassad logik (loggar, mätvärden, återställningar etc.). - Förfalskningar i tester med
Queue::fake()yBus::fake()för att verifiera att jobb, strängar eller batchar har skickats utan att de faktiskt körts.
I tester kan man ange saker som "detta jobb har köats X gånger" , "en kedja med dessa jobb har skickats i denna ordning" eller "inget särskilt jobb har köats", vilket ger mycket säkerhet i komplexa flöden.
Med hela detta ekosystem – drivrutiner som Redis eller SQS, väldesignade jobb, mellanprogramvara för finjustering, batchar, kedjor, konfiguration av återförsök, handledarehanterade arbetare och kommandon som queue:pause y queue:continue— Laravel låter dig bemästra bakgrundsbearbetning ner till millimetern, från typisk e-postutskickning till distribuerade köarkitekturer med redundans, vilket säkerställer att din applikation fortsätter att svara snabbt på HTTP-lagret medan tungt arbete utförs underifrån utan att blockera användaren.