Deze pagina richt zich op Laravel 13 en controleert de implementatie van Framework
v13.42.0. Ze gaat uit van de basis van queues en het testen van packages. Het compatibiliteitsontwerp hieronder is beleid aan de kant van het package. Laravel heeft geen functie die je eigen payloadformaten automatisch migreert.De code verandert tussen opslaan en uitvoeren
Bij objectjobs voertQueue::createObjectPayload() serialize(clone $job) uit en zet het resultaat in data.command van de payload. Bij versleuteling vindt dezelfde serialisatie daarvoor plaats.
Aan de workerkant voert CallQueuedHandler::getCommand() unserialize() uit op de opgeslagen data en geeft de herstelde job door aan de Dispatcher. Een gewone handle() draait met de code en de service container die de worker op dat moment heeft.
Als je langlopende workers niet herstart, blijft na de update de oude code draaien. Houd bij rolling deploys niet alleen rekening met “oude dispatcher met nieuwe worker”, maar ook met “nieuwe dispatcher met oude worker”.
Beoordeel het hernoemen of verwijderen van een klasse niet alleen op de vraag of gebruikers die klasse direct aanroepen. Wachtende, uitgestelde en op een nieuwe poging wachtende jobs, en de bewaartermijn van mislukte jobs, horen ook bij compatibiliteit.
Wat SerializesModels opslaat
Illuminate\Foundation\Queue\Queueable gebruikt intern SerializesModels. Naast het vervangen van modellen levert het __serialize(), dat de properties van de job zelf opsomt, en __unserialize(), dat de waarden terugzet.
Waarden gelijk aan de gedeclareerde standaardwaarde worden niet opgeslagen
__serialize() sluit statische en niet-geïnitialiseerde properties uit en slaat het opslaan ook over wanneer de huidige waarde strikt gelijk is aan de gedeclareerde standaardwaarde van de property.
'csv', dan bevat de opgeslagen array geen format. Verandert een latere release de gedeclareerde standaardwaarde in 'json', dan kan 'json' ook voor oude jobs gelden. Dat is geen cosmetische wijziging van de standaardwaarde, maar een wijziging in hoe oude data wordt gelezen.
De constructor wordt bij herstellen niet opnieuw aangeroepen
__unserialize() wijst waarden toe aan properties die in de huidige klasse bestaan en waarvoor de opgeslagen array een sleutel heeft. Aanvulling of validatie van invoer via de constructor vindt niet plaats.
'csv' in dit voorbeeld is de standaardwaarde van een constructorargument. Het is niet de gedeclareerde standaardwaarde van de property zelf, dus vult het de waarde niet aan wanneer je een oude payload zonder format herstelt. Blijft een toegevoegde getypeerde property niet-geïnitialiseerd, dan mislukt een latere toegang.
Verder is de sleutel van een public property haar naam, die van een protected property heeft een prefix voor de zichtbaarheid en die van een private property bevat ook de klassenaam. Controleer ook een wijziging van public naar private met oude payloads.
Identifiers en uitvoerende services scheiden
Sla de voor uitvoering benodigde identifiers en opties op in de job, en injecteer uitvoerende services zoals API-clients of exporters inhandle(). Geef je een service aan de constructor door en bewaar je die, dan kan ook haar interne toestand worden opgeslagen.
Het volgende voorbeeld voegt een formaatkeuze en een payloadversie toe aan een job met dezelfde naam die in de oude versie alleen reportId had. ReportExporter is een contract dat het package levert en in de container bindt, met export(string $reportId, string $format): void.
- Heeft een oude payload geen
format, dan wordt de gedeclareerde standaardwaarde'csv'gebruikt. - Heeft een oude payload geen
payloadVersion, dan wordt die behandeld als de gedeclareerde standaardwaarde1. - Bij nieuw aangemaakte jobs zet de constructor
payloadVersionop2. Omdat die afwijkt van de gedeclareerde standaardwaarde, wordt deze waarde opgeslagen. - Is de
formatvan een nieuwe job'json', dan wordt ook die waarde opgeslagen.'csv'wordt overgeslagen, dus houd de gedeclareerde standaardwaarde'csv'voortaan aan.
Doorgegeven modellen onderscheiden van snapshots
Sla je een model direct op in een property, dan vervangtSerializesAndRestoresModelIdentifiers het door een ModelIdentifier met klasse, ID, verbindingsnaam, namen van geladen relaties enzovoort. Bij het herstellen van één model haalt het dit opnieuw uit de database met firstOrFail() en laadt het de betreffende relaties.
Dit is geen mechanisme dat attributen of gerelateerde data vastlegt op het moment van dispatchen.
- Wordt het record vóór de uitvoering bijgewerkt, dan ziet het herstelde model de bijgewerkte inhoud.
- Vooraf op relaties toegepaste beperkingen worden niet opgeslagen, dus pas de benodigde voorwaarden bij uitvoering opnieuw toe.
- Sluit overbodige relaties uit van opslag met
withoutRelations()of#[WithoutRelations]. - Is het model verwijderd, dan kan de job al bij het herstellen mislukken, vóór zijn
handle().
#[DeleteWhenMissingModels] overwegen. Het package moet weggooien echter niet op eigen houtje de standaard maken, maar het faalbeleid aan gebruikers tonen. Geef je alleen een ID door en zoek je in handle(), dan bepaal je zelf hoe die zoekactie faalt of wordt overgeslagen.
Heb je de inhoud op het moment van dispatchen nodig, sla de benodigde waarden dan expliciet op, of leg bijvoorbeeld een onveranderlijk rapportverzoek vast in de database en geef het ID daarvan door. Onderscheid het simpelweg doorgeven van een model van het opslaan van een snapshot van bedrijfsdata.
Dispatchen na de commit is een apart probleem
Verwerk je records die binnen een transactie zijn aangemaakt, zorg dan dat workers ze niet vóór de commit gaan lezen.afterCommit() wacht met dispatchen tot de open bovenliggende transactie is gecommit en gooit de dispatch weg bij een rollback. Het lost de compatibiliteit van klassenamen en properties of het dubbel uitvoeren van externe verwerking niet op.
Fakes en tests van oude payloads scheiden
Een gewoneQueue::fake() registreert dispatches. Een geslaagde assertPushed() bevestigt op zich niet het opslaan en herstellen, of dat de nieuwe versie oude payloads verwerkt.
Een round trip met de huidige klasse controleer je zo.
serializeAndRestore() voert serialize() en unserialize() uit binnen de fake. Het controleert echter niet het dispatchen naar een echte backend, de uitvoering door een worker of het genereren door oude code.
Met de oude versie gegenereerde fixtures bewaren
Zolang de oudeGenerateReport alleen reportId heeft, genereer je een vaste job zonder echte data. De volgende voorbereidingscode voer je één keer uit in de testomgeving van de oude versie. Maak tests/fixtures/ vooraf aan.
TestCase in dit voorbeeld is de basisklasse die je in de testomgeving voor packages opzet. Geef aan unserialize() alleen fixtures die je zelf beheert, nooit externe invoer.
Voer daarnaast handle() van de herstelde oude job uit met een test-exporter en controleer de uitvoer en de opgeslagen resultaten. Geef je modellen door, controleer dan apart bijwerken, verwijderen, verbinding en het opnieuw ophalen van relaties, en op de queueverbinding die je echt gebruikt ook dispatchen na de commit en nieuwe pogingen.
De lezende kant bijwerken voordat je het nieuwe formaat dispatcht
1
Een release voorbereiden die het oude formaat kan lezen
Lever eerst code die de oude klassenaam en de interpretatie van oude waarden behoudt en ook het nieuwe formaat kan lezen. Controleer met fixtures niet alleen het herstellen, maar ook het verwerkingsresultaat.
2
Controleren dat er geen oude workers overblijven
Neem het vervangen van workers op in de deployprocedure van de gebruikende app. Bij een gewone
queue:work vraagt php artisan queue:restart om te stoppen na de huidige job, en je controleert dat de procesmanager de nieuwe versie start. Voor het herstartsignaal wordt de cache gebruikt.3
Het dispatchen van het nieuwe formaat inschakelen
Schakel pas over op het dispatchen van het nieuwe formaat wanneer de lezende kant het ondersteunt, bijvoorbeeld met een feature flag. Begint het uitrollen van dezelfde code al met het genereren van het nieuwe formaat, dan heb je een procedure nodig die het bij oude workers weghoudt, zoals het dispatchen pauzeren of oude en nieuwe queues met bijbehorende workers scheiden.
4
Ondersteuning behouden tijdens de periode voor nieuwe pogingen en rollback
Controleer ook nieuwe pogingen van mislukte jobs en jobs die later binnen chains worden gedispatcht. Ga je na het opslaan van het nieuwe formaat terug naar oude code, controleer dan of de oude code het kan lezen. Verwijder ondersteuning voor oude klassen of formaten niet alleen omdat de queue een keer leeg was.
queue:restart is geen commando dat opgeslagen payloads herschrijft. Vermeld in de update-instructies van het package de ondersteunde formaten, de benodigde vervanging van workers en de voorwaarden om het oude formaat af te schaffen. Leg dezelfde wijziging ook vast in versiecompatibiliteitsbeheer en changelogbeheer.
Geraadpleegde primaire bronnen
- Officiële Laravel-documentatie: structuur van jobs en dependency injection
- Officiële Laravel-documentatie: dispatchen na de commit
- Officiële Laravel-documentatie: workers en deployment
- Officiële Laravel-documentatie: omgaan met verwijderde modellen
- Queue: objectpayloads aanmaken
- Queueable: opbouw van de jobtrait
- SerializesModels: properties opslaan en herstellen
- SerializesAndRestoresModelIdentifiers: modellen vervangen en opnieuw ophalen
- CallQueuedHandler: herstellen en uitvoeren
- QueueFake: opslaan en herstellen in de fake
- Officiële Laravel-tests: serialisatie van modellen