Differire i compiti in Laravel usando le code

In questo articolo, esploreremo l'API Queue nel framework web di Laravel. Consente di rinviare le attività ad alta intensità di risorse durante l'esecuzione dello script per migliorare l'esperienza generale dell'utente finale. Dopo aver introdotto la terminologia di base, lo dimostrerò implementando un esempio reale.

Il tempo di caricamento delle pagine è un aspetto importante di qualsiasi sito web di successo e non bisogna trascurare l'importanza di questo dato che influisce sulla SEO del sito e sull'esperienza complessiva dell'utente finale. Più spesso, si finisce per dover eseguire il debug di pagine Web con tempi di caricamento lunghi della pagina. Naturalmente, ci sono diversi approcci che potresti usare per correggere questo problema.

Dopo un'indagine, capisci spesso che ci sono determinati blocchi di codice che causano un ritardo nell'esecuzione della pagina. La prossima cosa che potresti provare è identificare blocchi che possono essere differiti per l'elaborazione e che non hanno alcun impatto reale sul risultato finale della pagina corrente. Questo dovrebbe davvero migliorare la velocità generale della pagina web in quanto abbiamo eliminato i blocchi di codice che causavano un ritardo.

Oggi, esploreremo un concetto simile nel contesto del framework web di Laravel. In effetti, Laravel fornisce già un'utile API integrata che ci consente di rinviare l'elaborazione delle attività, l'API della coda. Senza perdere molto del tuo tempo, andrò avanti e discuterò gli elementi di base dell'API Queue.

Driver, connessioni, code e lavori

Lo scopo principale dell'API Queue è eseguire i lavori che vengono aggiunti in una coda. Successivamente, la coda potrebbe appartenere a una connessione specifica e tale connessione potrebbe appartenere a un driver di coda specifico configurato con tale connessione stessa. Cerchiamo brevemente di capire cosa ho appena detto.

Driver della coda

Allo stesso modo, avresti usato un driver diverso per la tua connessione al database, potresti anche scegliere tra una varietà di diversi driver di coda. L'API della coda supporta diversi adattatori come database, beanstalkd, sqs e redis.

Il driver di coda è solo un posto che viene utilizzato per memorizzare le informazioni relative alla coda. Pertanto, se si utilizza un driver di coda del database, ad esempio, il nuovo lavoro verrà aggiunto nella tabella dei lavori nel database. D'altra parte, se hai configurato redis come driver di coda predefinito, il lavoro verrà aggiunto al server redis.

L'API della coda fornisce anche due driver speciali per le code a scopo di test: sincronizzazione e null. Il driver della coda di sincronizzazione viene utilizzato per eseguire immediatamente un processo di coda, mentre il driver della coda nulla viene utilizzato per saltare un lavoro in modo che non venga eseguito affatto.

Connessioni

Quando si configura l'API della coda per la prima volta, è necessario specificare una connessione predefinita da utilizzare per l'elaborazione della coda predefinita. Per lo meno, la connessione dovrebbe fornire le seguenti informazioni:

  • il driver della coda che verrà utilizzato
  • i valori di configurazione specifici del driver della coda
  • il nome della coda di default in cui verrà aggiunto il lavoro

code

Quando aggiungi un lavoro in una coda, verrà aggiunto alla coda predefinita. In realtà, nella maggior parte dei casi dovrebbe andare bene, a meno che non si abbiano lavori a cui è necessario dare maggiore priorità rispetto ad altri lavori. In tal caso, è possibile creare una coda denominata alto e posizionare i lavori con priorità più alta in quella particolare coda.

Quando si esegue una coda che elabora lavori in coda, è possibile passare facoltativamente --coda parametro, che consente di elencare i nomi delle code nell'ordine in cui devono essere elaborati. Ad esempio, se si specifica --code = alto, di default, per prima cosa elaborerà i lavori nel alto coda, e una volta completata, recupera i lavori nella coda predefinita.

Lavori

Un lavoro nell'API coda è un'attività che viene differita dal flusso di esecuzione principale. Ad esempio, se si desidera creare una miniatura quando l'utente carica un'immagine dal front-end, è possibile creare un nuovo lavoro che gestisca l'elaborazione della miniatura. In questo modo, è possibile rinviare l'attività di elaborazione delle miniature dal flusso di esecuzione principale.

Questa era un'introduzione di base alla terminologia dell'API Queue. Dalla prossima sezione in poi, esploreremo come creare un lavoro di coda personalizzato ed eseguirlo usando un operatore di coda di Laravel.

Crea il tuo primo lavoro in coda

A questo punto, dovresti sentirti sicuro riguardo ai lavori in coda. Da questa sezione in poi, implementeremo un esempio reale che dimostra il concetto di lavori in coda in Laravel.

Più spesso, si finisce nella situazione in cui è necessario creare diverse versioni di anteprima di un'immagine caricata da un utente. Nella maggior parte dei casi, lo sviluppatore tenta di elaborarlo in tempo reale in modo che vengano create immediatamente diverse versioni di immagini quando l'utente carica un'immagine.

Sembra un approccio ragionevole se creerai un paio di versioni e non ci vorrà troppo tempo. D'altra parte, se hai a che fare con un'applicazione che richiede un'elaborazione pesante e quindi consuma più risorse, l'elaborazione in tempo reale potrebbe finire in una brutta esperienza utente.

L'ovvia opzione che ti viene in mente in primo luogo è quella di posticipare l'elaborazione della generazione delle miniature il più tardi possibile. L'approccio più semplice che potresti implementare in questo specifico scenario è impostare un cron job che attivi l'elaborazione ad intervalli regolari, e dovresti stare bene.

Un approccio molto migliore, d'altra parte, è di posticipare e spingere l'attività in una coda, e lasciare che l'elaboratore della coda la elabori quando ha la possibilità di farlo. In un ambiente di produzione, il gestore code è uno script daemon che è sempre in esecuzione e che elabora le attività in una coda. L'ovvio vantaggio di questo approccio è una migliore esperienza dell'utente finale e non è necessario attendere la cron run poiché il lavoro verrà elaborato il prima possibile.

Suppongo che sia sufficiente una teoria per iniziare con un'implementazione reale.

Nel nostro caso, useremo il Banca dati driver di coda, e ci richiede di creare il lavori tabella nel database. Il lavori la tabella contiene tutti i lavori che devono essere elaborati nella prossima esecuzione della coda di lavoro.

Prima di andare avanti e creare il lavori tabella, cambiamo la configurazione della coda predefinita da sincronizzare a Banca dati nel config / queue.php file.

... / * | ---------------------------------------------- ---------------------------- | Default Queue Driver | ---------------------------------------------- ---------------------------- | | L'API della coda di Laravel supporta un assortimento di back-end tramite un singolo | API, offrendoti un comodo accesso a ciascun back-end utilizzando lo stesso | sintassi per ognuno. Qui puoi impostare il driver di coda predefinito. | | Supportato: "sync", "database", "beanstalkd", "sqs", "redis", "null" | * / 'default' => env ('QUEUE_DRIVER', 'database'), ... 

In effetti, Laravel fornisce già un comando artigianale che ci aiuta a creare il lavori tavolo. Esegui il seguente comando nella root della tua applicazione Laravel, e dovrebbe creare la necessaria migrazione del database che crea il lavori tavolo.

Coda artigianale $ php: tabella

Il file di migrazione generato in Database / migrazioni / YYYY_MM_DD_HHMMSS_create_jobs_table.php dovrebbe assomigliare a questo:

bigIncrements ( 'id'); $ Tavola-> string ( 'coda'); $ Tavola-> LongText ( 'payload'); $ Tavola-> unsignedTinyInteger ( 'tentativi'); $ Tavola-> unsignedInteger ( 'reserved_at') -> nullable (); $ Tavola-> unsignedInteger ( 'available_at'); $ Tavola-> unsignedInteger ( 'created_at'); $ table-> index (['queue', 'reserved_at']); );  / ** * Invertire le migrazioni. * * @return void * / public function down () Schema :: dropIfExists ('jobs');  

Quindi, eseguiamo il migrare comando in modo che in realtà crei il lavori tabella in un database.

php artisan migrate

Questo è fino al lavori la migrazione è preoccupata.

Quindi, creiamo il Immagine modello che verrà utilizzato per gestire le immagini caricate dall'utente finale. Il modello di immagine richiede anche una tabella di database associata, quindi useremo il --migrare opzione durante la creazione di Immagine modello.

php artigianale: modello Immagine - migrazione

Il comando precedente dovrebbe creare il Immagine modello di classe e una migrazione del database associato pure.

Il Immagine la classe del modello dovrebbe assomigliare a questa:

E il file di migrazione del database dovrebbe essere creato su Database / migrazioni / YYYY_MM_DD_HHMMSS_create_images_table.php. Vogliamo anche memorizzare il percorso originale dell'immagine caricata dall'utente finale. Rivediamo il codice del Immagine file di migrazione del database per assomigliare al seguente.

incrementi ( 'id'); $ Tavola-> timestamp (); $ Tavola-> string ( 'org_path'); );  / ** * Invertire le migrazioni. * * @return void * / public function down () Schema :: dropIfExists ('images'); 

Come puoi vedere, abbiamo aggiunto il $ Tavola-> string ( 'org_path') colonna per memorizzare il percorso dell'immagine originale. Quindi, devi solo eseguire il migrare comando per creare effettivamente quella tabella nel database.

$ php artisan migrate

E questo è fino al Immagine modello è interessato.

Successivamente, creiamo un processo di coda effettivo responsabile dell'elaborazione delle miniature delle immagini. Per l'elaborazione delle miniature, utilizzeremo una libreria di elaborazione delle immagini molto popolare: l'immagine di intervento.

Per installare la libreria Image di Intervention, andare avanti ed eseguire il seguente comando nella directory principale dell'applicazione.

$ php composer.phar richiede l'intervento / immagine

Ora è il momento di creare il Lavoro classe, e useremo un comando artigiano per farlo.

$ php artisan make: job ProcessImageThumbnails

Quello dovrebbe creare il Lavoro modello di classe a app / Lavoro / ProcessImageThumbnails.php. Sostituiamo il contenuto di quel file con il seguente.

immagine = $ immagine;  / ** * Esegui il lavoro. * * @return void * / public function handle () // accede al modello in coda per l'elaborazione $ image = $ this-> image; $ full_image_path = public_path ($ image-> org_path); $ resized_image_path = public_path ('thumbs'. DIRECTORY_SEPARATOR. $ image-> org_path); // crea immagini thumb dall'immagine originale $ img = \ Image :: make ($ full_image_path) -> ridimensiona (300, 200); $ Img-> save ($ resized_image_path); 

Quando l'addetto alla coda inizia a elaborare un lavoro, cerca maniglia metodo. Quindi è il maniglia metodo che mantiene la logica principale del tuo lavoro.

Nel nostro caso, dobbiamo creare una miniatura di un'immagine caricata dall'utente. Il codice del maniglia il metodo è piuttosto semplice: recuperiamo un'immagine dal ImageModel modella e crea una miniatura utilizzando la libreria Immagine di intervento. Certo, dobbiamo passare il corrispondente Immagine modello quando spediamo il nostro lavoro, e lo vedremo tra un momento.

Per testare il nostro lavoro appena creato, creeremo un semplice modulo di caricamento che consente all'utente di caricare un'immagine. Naturalmente, non creeremo le miniature delle immagini subito; differiremo quell'attività in modo che possa essere elaborata dall'operatore della coda.

Creiamo un file di controller su app / Http / Controller / ImageController.php come mostrato di seguito.

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']); // crea una voce db di quell'immagine $ image = new Image; $ image-> org_path = 'images'. DIRECTORY_SEPARATOR. $ Input [ 'demo_image']; $ Immagine-> save (); // posticipa l'elaborazione delle miniature dell'immagine ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> with ('message', 'Immagine caricata con successo!'); 

Creiamo un file di visualizzazione associato a Resources / views / upload_form.blade.php.

       laravel       
@if (Route :: has ('login')))
@if (Auth :: check ()) Home @else Accedi Register @endif
@finisci se

Modulo di caricamento demo

@if ($ errors-> any ())
    @foreach ($ errors-> all () come $ errore)
  • $ error
  • @endforeach
@endif @if (sessione ('messaggio'))
sessione ('messaggio')
@finisci se

Infine, aggiungiamo percorsi per il indice e caricare azioni nel percorsi / web.php file.

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

Nel ImageController controller, il indice il metodo è usato per rendere un modulo di upload.

indice di funzione pubblica (richiesta $ richiesta) visualizzazione di ritorno ('upload_form'); 

Quando l'utente invia un modulo, il caricare il metodo è invocato.

upload di funzioni pubbliche (richiesta $ richiesta) // carica immagine $ this-> convalida ($ 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']); // crea una voce db di quell'immagine $ image = new Image; $ image-> org_path = 'images'. DIRECTORY_SEPARATOR. $ Input [ 'demo_image']; $ Immagine-> save (); // posticipa l'elaborazione delle miniature dell'immagine ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> with ('message', 'Immagine caricata con successo!'); 

All'inizio del caricare metodo, noterai il solito codice di caricamento del file che sposta il file caricato nel file / immagini pubbliche directory. Successivamente, inseriamo un record del database usando il App / Immagine modello.

Finalmente, usiamo il ProcessImageThumbnails lavoro per rinviare l'attività di elaborazione delle miniature. È importante notare che è il spedizione metodo utilizzato per rinviare un'attività. Alla fine, l'utente viene reindirizzato alla pagina di caricamento con un messaggio di successo.

A questo punto nel tempo, il lavoro viene aggiunto al lavori tavolo per l'elaborazione. Confermiamo inviando la seguente domanda.

mysql> seleziona * FROM lvl_jobs; | 1 | default |  "DisplayName": "App \\ Lavoro \\ ProcessImageThumbnails", "lavoro": "Illuminare \\ coda \\ CallQueuedHandler @ chiamare", "maxTries": null, "timeout": "dati" null,:  "CommandName ":" App \\ Lavoro \\ ProcessImageThumbnails " "comando": "O: 31: \" App \\ Jobs \\ ProcessImageThumbnails \ ": 5: s: 8: \" \ u0000 * \ u0000image \"; O: 45: \ "Illuminate \\ \\ Contratti di database \\ ModelIdentifier \": 2: s: 5: \ "classe \"; s: 9: \ "App \\ Immagine \"; s: 2: \ "id \"; i: 2; s: 6: \ "\ u0000 * \ u0000job \"; N; s: 10: \ "collegamento \"; N; s: 5: \ "coda \"; N; s: 5: \ "delay \"; N; " | 0 | NULL | 1510219099 | 1510219099 |

Ti starai chiedendo, cosa serve per elaborare un lavoro, allora? Non preoccuparti, è quello che discuteremo nella prossima sezione.

Queue Worker

Il lavoro del responsabile della coda di Laravel consiste nell'elaborare i lavori che vengono messi in coda per l'elaborazione. Di fatto, esiste un comando artigiano che ci aiuta ad avviare il processo di lavoro in coda.

Coda artigianale $ php: lavoro

Non appena esegui quel comando, elabora i lavori in sospeso. Nel nostro caso, dovrebbe elaborare il ProcessImageThumbnails lavoro che è stato messo in coda quando l'utente ha caricato un'immagine in precedenza.

$ php artisan queue: work [YYYY-MM-DD HHMMSS] Elaborazione: App \ Jobs \ ProcessImageThumbnails [AAAA-MM-GG HHMMSS] Elaborato: App \ Jobs \ ProcessImageThumbnails

Avresti notato che quando avvii un addetto alla coda, continua a funzionare finché non lo uccidi manualmente o chiudi il terminale. In realtà, è in attesa che il prossimo lavoro venga elaborato. Non appena c'è un nuovo lavoro in coda, verrà elaborato immediatamente se l'addetto alla coda è in esecuzione.

Ovviamente, non possiamo mantenerlo in esecuzione in questo modo, quindi dobbiamo trovare un modo per far sì che l'addetto alla coda funzioni in modo permanente in background.

Per il nostro salvataggio, ci sono diversi strumenti di gestione dei processi che puoi scegliere. Per citarne alcuni, ecco un elenco:

  • Circo
  • strumenti del demonio
  • Monit
  • Supervisore
  • parvenu

Dovresti scegliere uno strumento con cui ti senti a tuo agio per gestire il gestore della coda di Laravel. Fondamentalmente, vogliamo essere sicuri che l'addetto alla coda debba essere eseguito a tempo indeterminato in modo che elabori immediatamente i lavori in coda.

Quindi questa è l'API della coda a tua disposizione. È possibile utilizzarlo nello sviluppo quotidiano per rinviare le attività che richiedono tempo per migliorare l'esperienza dell'utente finale.

Conclusione

In questo articolo, abbiamo discusso l'API Queue in Laravel, che è davvero utile se si desidera rinviare l'elaborazione di attività che consumano risorse.

Abbiamo iniziato con un'introduzione di base all'API Queue, che prevedeva una discussione su connessioni, code e lavori. Nella seconda metà dell'articolo, abbiamo creato un processo di coda personalizzato che dimostrava come utilizzare l'API Queue nel mondo reale.

Per quelli di voi che stanno appena iniziando con Laravel o stanno cercando di espandere le vostre conoscenze, il vostro sito o la vostra applicazione con estensioni, abbiamo una varietà di cose che potete studiare nel mercato Envato.

Sentiti libero di utilizzare il modulo di feedback qui sotto per pubblicare domande e suggerimenti.