Uitstel van taken in Laravel met behulp van wachtrijen

In dit artikel gaan we de Queue API in het Laravel-webraamwerk verkennen. Hiermee kunt u tijdens de scriptuitvoering resource-intensieve taken uitstellen om de algehele eindgebruikerservaring te verbeteren. Na het introduceren van de basisterminologie, zal ik het demonstreren door een realistisch voorbeeld te implementeren.

De laadtijd van de pagina is een belangrijk aspect van elke succesvolle website en het belang hiervan mag niet over het hoofd worden gezien, omdat dit ook van invloed is op de SEO van de site en de algehele ervaring van de eindgebruiker. Vaker wel dan niet, moet u uiteindelijk webpagina's debuggen met lange laadtijd van pagina's. Natuurlijk zijn er verschillende benaderingen die u zou kunnen gebruiken om dit probleem te verhelpen.

Bij onderzoek realiseert u zich vaak dat bepaalde codeblokken een vertraging in de uitvoering van de pagina veroorzaken. Het volgende dat u kunt proberen, is het identificeren van blokken die kunnen worden uitgesteld voor verwerking en die geen echte invloed hebben op het eindresultaat van de huidige pagina. Dat zou de algehele webpagina-snelheid echt moeten verbeteren, omdat we de codeblokken hebben verwijderd die een vertraging veroorzaakten.

Vandaag gaan we een soortgelijk concept verkennen in de context van het Laravel-webraamwerk. Laravel biedt al een bruikbare ingebouwde API waarmee we de verwerking van taken kunnen uitstellen, de wachtrij-API. Zonder veel tijd te verspillen, bespreek ik de basiselementen van de Queue API.

Stuurprogramma's, verbindingen, wachtrijen en taken

Het basisdoel van de Queue API is om taken uit te voeren die in een wachtrij zijn toegevoegd. De wachtrij zou vervolgens kunnen behoren tot een specifieke verbinding en die verbinding kan tot een specifiek wachtrijstuurprogramma behoren dat met die verbinding zelf is geconfigureerd. Laten we even proberen te begrijpen wat ik net heb gezegd.

Wachtrij-stuurprogramma's

Op dezelfde manier zou u een ander stuurprogramma voor uw databaseverbinding hebben gebruikt, u zou ook uit een groot aantal verschillende wachtrijstuurprogramma's kunnen kiezen. De Queue API ondersteunt verschillende adapters zoals database, beanstalkd, sqs en redis.

Het wachtrijstuurprogramma is slechts een plaats die wordt gebruikt om aan wachtrij gerelateerde informatie op te slaan. Dus als u bijvoorbeeld een databasewachtrij-stuurprogramma gebruikt, wordt de nieuwe taak toegevoegd aan de taaptabel in de database. Als u daarentegen opnieuw hebt ingesteld als het standaardwachtrijstuurprogramma, wordt de taak toegevoegd aan de redis-server.

De Queue API biedt ook twee speciale wachtrij-stuurprogramma's voor testdoeleinden: synchroniseren en null. Het synchrone wachtrijstuurprogramma wordt gebruikt om een ​​wachtrijtaak onmiddellijk uit te voeren, terwijl het nulwachtrijstuurprogramma wordt gebruikt om een ​​taak over te slaan zodat deze helemaal niet wordt uitgevoerd.

aansluitingen

Wanneer u de wachtrij-API voor de eerste keer configureert, moet u een standaardverbinding opgeven die moet worden gebruikt voor de standaardwachtrijverwerking. Op zijn minst zal de verbinding naar verwachting de volgende informatie opleveren:

  • de wachtrijdriver die zal worden gebruikt
  • de specifieke configuratiewaarden van de wachtrijdriver
  • de standaard wachtrijnaam waarin de taak zal worden toegevoegd

wachtrijen

Wanneer u een taak aan een wachtrij toevoegt, wordt deze aan de standaardwachtrij toegevoegd. In feite zou dat in de meeste gevallen goed moeten zijn, tenzij je banen hebt die een hogere prioriteit moeten krijgen boven andere banen. In dat geval zou u een wachtrij kunnen maken met de naam hoog en plaats de jobs met hogere prioriteit in die specifieke wachtrij.

Wanneer u een wachtrijwerknemer uitvoert die taken in de wachtrij verwerkt, kunt u optioneel de --wachtrij parameter, waarmee u namen van wachtrijen kunt weergeven in de volgorde waarin ze moeten worden verwerkt. Bijvoorbeeld, als u opgeeft --wachtrij = hoog, default, het zal eerst banen verwerken in de hoog wachtrij en zodra deze is voltooid, worden taken opgehaald in de standaardwachtrij.

Jobs

Een taak in de wachtrij-API is een taak die wordt uitgesteld van de hoofduitvoerstroom. Als u bijvoorbeeld een miniatuur wilt maken wanneer de gebruiker een afbeelding vanaf de front-end uploadt, kunt u een nieuwe taak maken die de miniatuurverwerking verwerkt. Op deze manier kunt u de taak van de miniatuurbewerking uit de hoofduitvoeringsstroom uitstellen.

Dat was een basisinleiding voor de terminologie van de wachtrij-API. In het volgende gedeelte zullen we onderzoeken hoe een aangepaste wachtrijtaak kan worden gemaakt en uitgevoerd met behulp van een Laravel-wachtrijmedewerker.

Maak uw eerste wachttaak aan

Inmiddels moet u vertrouwen hebben in wachtrijjobs. In dit gedeelte gaan we een realistisch voorbeeld implementeren dat het concept van wachtrijtaken in Laravel laat zien.

Vaker wel dan niet, kom je in de situatie terecht waarin je verschillende thumbnail-versies van een door een gebruiker geuploade afbeelding moet maken. In de meeste gevallen probeert de ontwikkelaar het in realtime te verwerken, zodat er meteen verschillende versies van afbeeldingen worden gemaakt wanneer de gebruiker een afbeelding uploadt.

Het lijkt een redelijke benadering als je een paar versies gaat maken en het neemt in de eerste plaats niet te veel tijd in beslag. Aan de andere kant, als u te maken hebt met een toepassing die zware verwerking vereist en dus meer bronnen ophaalt, kan real-time verwerking resulteren in een slechte gebruikerservaring.

De voor de hand liggende optie die in de eerste plaats opduikt, is om de verwerking van de miniatuurgeneratie zo laat mogelijk uit te stellen. De eenvoudigste benadering die u in dit specifieke scenario kunt implementeren, is het instellen van een cron-taak waarmee de verwerking met regelmatige tussenpozen wordt gestart..

Een veel betere aanpak is echter om de taak uit te stellen en de taak in een wachtrij te plaatsen en de wachtrijmedewerker deze te laten verwerken wanneer hij de kans krijgt om dit te doen. In een productieomgeving is de wachtrijwerker een daemon-script dat altijd wordt uitgevoerd en taken in een wachtrij verwerkt. Het voor de hand liggende voordeel van deze aanpak is een veel betere eindgebruikerservaring en u hoeft niet te wachten op de cron-run, omdat de taak zo snel mogelijk wordt verwerkt..

Ik denk dat dat genoeg theorie is om aan de slag te gaan met een daadwerkelijke implementatie.

In ons geval gaan we het gebruiken databank wachtrijstuurprogramma en dit vereist dat we het jobs tabel in de database. De jobs tabel bevat alle taken die moeten worden verwerkt in de volgende rij van de wachtrijwerknemer.

Voordat we doorgaan en het maken jobs tabel, laten we de standaardwachtrijconfiguratie wijzigen van synchroniseren naar databank in de config / queue.php het dossier.

... / * | ---------------------------------------------- ---------------------------- | Default Queue Driver | ---------------------------------------------- ---------------------------- | | Laravel's wachtrij-API ondersteunt een assortiment back-ends via een enkele | API, waarmee u gemakkelijk toegang hebt tot elke back-end met dezelfde | syntaxis voor elk. Hier kunt u het standaard wachtrijstuurprogramma instellen. | | Ondersteund: "sync", "database", "beanstalkd", "sqs", "redis", "null" | * / 'standaard' => env ('QUEUE_DRIVER', 'database'), ... 

In feite biedt Laravel al een ambachtelijk commando dat ons helpt om het jobs tafel. Voer de volgende opdracht uit in de hoofdmap van uw Laravel-toepassing en maak de benodigde databasemigratie die de jobs tafel.

$ php artisan-wachtrij: tabel

Het migratiebestand dat is gegenereerd op databank / migraties / YYYY_MM_DD_HHMMSS_create_jobs_table.php zou er als volgt uit moeten zien:

bigIncrements ( 'id'); $ Tafel-> string ( 'wachtrij'); $ Tafel-> longtext ( 'payload'); $ Tafel-> unsignedTinyInteger ( 'pogingen'); $ Tafel-> unsignedInteger ( 'reserved_at') -> vernietigbaar (); $ Tafel-> unsignedInteger ( 'available_at'); $ Tafel-> unsignedInteger ( 'created_at'); $ table-> index (['queue', 'reserved_at']); );  / ** * Keer de migraties terug. * * @return void * / public function down () Schema :: dropIfExists ('jobs');  

Laten we vervolgens de trekken commando zodat het daadwerkelijk de jobs tabel in een database.

php artisan migreren

Dat is het voor zover als het jobs migratie betreft.

Laten we vervolgens de Beeld model dat zal worden gebruikt om afbeeldingen te beheren die door de eindgebruiker zijn geüpload. Het afbeeldingsmodel vereist ook een bijbehorende databasetabel, dus we gebruiken de --trekken optie tijdens het maken van de Beeld model-.

php artisan make: model Afbeelding - migratie

Het bovenstaande commando zou het moeten maken Beeld modelklasse en een bijbehorende databasemigratie.

De Beeld modelklasse zou er als volgt uit moeten zien:

En het database-migratiebestand zou moeten worden aangemaakt bij databank / migraties / YYYY_MM_DD_HHMMSS_create_images_table.php. We willen ook het originele pad van de afbeelding opslaan die door de eindgebruiker is geüpload. Laten we de code van de Beeld databasemigratiebestand om er als volgt uit te zien.

verhogingen ( 'id'); $ Tafel-> timestamps (); $ Tafel-> string ( 'org_path'); );  / ** * Keer de migraties terug. * * @return void * / public function down () Schema :: dropIfExists ('images'); 

Zoals u kunt zien, hebben we het $ Tafel-> string ( 'org_path') kolom om het pad van de originele afbeelding op te slaan. Vervolgens moet u gewoon de trekken opdracht om die tabel daadwerkelijk in de database te maken.

$ php artisan migreren

En dat is het voor zover als het Beeld model betreft.

Laten we vervolgens een echte wachtrijtaak maken die verantwoordelijk is voor het verwerken van afbeeldingsminiaturen. Voor de miniatuurverwerking gebruiken we een zeer populaire beeldverwerkingsbibliotheek - Intervention Image.

Om de Intervention Image-bibliotheek te installeren, moet u de volgende opdracht uitvoeren in de hoofdmap van uw toepassing.

$ php composer.phar vereist een interventie / afbeelding

Nu is het tijd om het te maken job klasse, en we zullen een ambachtelijk commando gebruiken om dat te doen.

$ php artisan make: job ProcessImageThumbnails

Dat zou het moeten maken job class template at app / Banen / ProcessImageThumbnails.php. Laten we de inhoud van dat bestand vervangen door het volgende.

afbeelding = $ afbeelding;  / ** * Voer de taak uit. * * @return void * / public function handle () // toegang tot het model in de wachtrij voor verwerking $ image = $ this-> image; $ full_image_path = public_path ($ image-> org_path); $ resized_image_path = public_path ('thumbs'. DIRECTORY_SEPARATOR. $ image-> org_path); // maak afbeeldingduimen van de originele afbeelding $ img = \ Afbeelding :: make ($ full_image_path) -> formaat wijzigen (300, 200); $ Img-> save ($ resized_image_path); 

Wanneer de wachtrijmedewerker begint met het verwerken van een taak, zoekt deze naar de handvat methode. Dus het is het handvat methode die de hoofdlogica van uw taak bevat.

In ons geval moeten we een miniatuur maken van een afbeelding die door de gebruiker is geüpload. De code van de handvat methode is vrij eenvoudig - we halen een afbeelding uit de ImageModel model en maak een miniatuur met behulp van de Intervention Image-bibliotheek. Natuurlijk moeten we het overeenkomstige doorgeven Beeld model wanneer we onze baan verzenden, en we zullen het zo meteen zien.

Om onze nieuw gecreëerde taak te testen, maken we een eenvoudig uploadformulier waarmee de gebruiker een afbeelding kan uploaden. Natuurlijk zullen we niet meteen beeldminiaturen maken; we stellen die taak uit zodat deze kan worden verwerkt door de wachtrijmedewerker.

Laten we een controllerbestand maken op app / Http / Controllers / ImageController.php zoals hieronder getoond.

validate ($ request, ['demo_image' => 'required | image | mimes: jpeg, png, jpg, gif, svg | max: 2048',]); $ image = $ request-> file ('demo_image'); $ input ['demo_image'] = time (). '.'. $ image-> getClientOriginalExtension (); $ destinationPath = public_path ('/ images'); $ image-> move ($ destinationPath, $ input ['demo_image']); // make db entry van die afbeelding $ image = new Image; $ image-> org_path = 'afbeeldingen'. DIRECTORY_SEPARATOR. $ Ingang [ 'demo_image']; $ Beeld-> save (); // uitstellen van de verwerking van de afbeeldingsminiaturen ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> with ('message', 'Afbeelding succesvol geüpload!'); 

Laten we een gekoppeld weergavebestand maken op resources / views / upload_form.blade.php.

       Laravel       
@if (Route :: has ('login'))
@if (Auth :: check ()) Home @else Inloggen Registreren @endif
@stop als

Demo-uploadformulier

@if ($ errors-> any ())
    @foreach ($ errors-> all () als $ fout)
  • $ fout
  • @endforeach
@endif @if (sessie ('bericht'))
session ('message')
@stop als

Laten we tot slot routes toevoegen voor de inhoudsopgave en uploaden acties in de routes / web.php het dossier.

Route :: get ('image / index', 'ImageController @ index'); Route :: post ('afbeelding / upload', 'ImageController @ upload');

In de ImageController controller, de inhoudsopgave methode wordt gebruikt om een ​​uploadformulier te renderen.

openbare functie-index (verzoek $ aanvraag) return view ('upload_form'); 

Wanneer de gebruiker een formulier verzendt, wordt de uploaden methode wordt aangeroepen.

public function upload (Request $ request) // upload afbeelding $ this-> validate ($ request, ['demo_image' => 'vereist | afbeelding | mimespelers: jpeg, png, jpg, gif, svg | max: 2048', ]); $ image = $ request-> file ('demo_image'); $ input ['demo_image'] = time (). '.'. $ image-> getClientOriginalExtension (); $ destinationPath = public_path ('/ images'); $ image-> move ($ destinationPath, $ input ['demo_image']); // make db entry van die afbeelding $ image = new Image; $ image-> org_path = 'afbeeldingen'. DIRECTORY_SEPARATOR. $ Ingang [ 'demo_image']; $ Beeld-> save (); // uitstellen van de verwerking van de afbeeldingsminiaturen ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> with ('message', 'Afbeelding succesvol geüpload!'); 

Aan het begin van de uploaden methode, zult u de gebruikelijke bestandsuploadcode opmerken die het geüploade bestand naar de publiek / images directory. Vervolgens voegen we een databaserecord in met behulp van de App / Beeld model-.

Ten slotte gebruiken we de ProcessImageThumbnails taak om de miniatuurverwerkingstaak uit te stellen. Het is belangrijk op te merken dat het de verzending methode die wordt gebruikt om een ​​taak uit te stellen. Aan het eind wordt de gebruiker omgeleid naar de uploadpagina met een succesbericht.

Op dit moment wordt de taak toegevoegd aan de jobs tabel voor verwerking. Laten we het bevestigen door de volgende query uit te voeren.

mysql> selecteer * FROM lvl_jobs; | 1 | standaard |  "Selecteer": "App \\ Jobs \\ ProcessImageThumbnails", "job": "Verlicht \\ Queue \\ CallQueuedHandler @ noemen", "maxTries": null, "time-out": null, "data":  "commandonaam ":" App \\ Jobs \\ ProcessImageThumbnails " "opdracht": "O: 31: \" App \\ Jobs \\ ProcessImageThumbnails \ ": 5: s: 8: \" \ u0000 * \ u0000image \"; O: 45: \ "Illuminate \\ Contracten \\ Database \\ ModelIdentifier \": 2: s: 5: \ "class \"; s: 9: \ "App \\ Image \"; s: 2: \ "id \"; i: 2; s: 6: \ "\ u0000 * \ u0000job \" N; s: 10: \ "verbinding \" N; s: 5: \ "file \", N; s: 5: \ "delay \"; N; " | 0 | NULL | 1510219099 | 1510219099 |

Je moet je afvragen, wat is er dan nodig om een ​​baan te verwerken? Maak je geen zorgen, dat is wat we in het volgende gedeelte gaan bespreken.

Wachtrijwerknemer

Het is de taak van de Laravel-wachtrijmedewerker om taken te verwerken die in de wachtrij staan ​​voor verwerking. In feite is er een ambachtelijk commando dat ons helpt om het wachtrijwerkproces te starten.

$ php artisan-wachtrij: werk

Zodra u die opdracht uitvoert, worden wachtende taken verwerkt. In ons geval zou het het moeten verwerken ProcessImageThumbnails taak die in de wachtrij is geplaatst toen de gebruiker een afbeelding eerder uploadde.

$ php artisan queue: work [YYYY-MM-DD HHMMSS] Verwerking: App \ Jobs \ ProcessImageThumbnails [JJJJ-MM-DD HHMMSS] Verwerkt: App \ Jobs \ ProcessImageThumbnails

Het zou je zijn opgevallen dat wanneer je een wachtrijmedewerker opstart, deze blijft werken tot je hem handmatig doodt of de terminal sluit. In feite wacht het tot de volgende taak wordt verwerkt. Zodra er een nieuwe taak in de wachtrij staat, wordt deze meteen verwerkt als de wachtrijmedewerker actief is.

We kunnen het natuurlijk niet zo houden, dus we moeten een manier vinden waarop de wachtrijmedewerker permanent op de achtergrond kan worden uitgevoerd.

Tot onze redding zijn er verschillende tools voor procesbeheer waar je uit kunt kiezen. Om een ​​paar te noemen, hier is een lijst:

  • Circus
  • Daemon Tools
  • Monit
  • Leidinggevende
  • Parvenu

U moet een hulpmiddel kiezen waarmee u vertrouwd bent om de Laravel-wachtrijmedewerker te beheren. Kortom, we willen er zeker van zijn dat de wachtrijmedewerker voor onbepaalde tijd moet werken, zodat hij onmiddellijk wachtrijen verwerkt..

Dus dat is de Queue API tot uw beschikking. U kunt het bij uw dagelijkse ontwikkeling gebruiken om tijdrovende taken uit te stellen om de eindgebruikerservaring te verbeteren.

Conclusie

In dit artikel hebben we de wachtrij-API besproken in Laravel, wat erg handig is als je de verwerking van resource-intensieve taken wilt uitstellen.

We zijn begonnen met een basisinleiding van de Queue API, die een bespreking van verbindingen, wachtrijen en taken omvatte. In de tweede helft van het artikel hebben we een aangepaste wachtrijjob gemaakt die aantoonde hoe je de Queue API in de echte wereld kon gebruiken.

Voor degenen onder u die net zijn begonnen met Laravel of die op zoek zijn om uw kennis, site of applicatie uit te breiden met uitbreidingen, hebben we een aantal dingen die u kunt bestuderen in Envato Market.

Voel je vrij om het onderstaande feedbackformulier te gebruiken om je vragen en suggesties te plaatsen.