Report de tâches dans Laravel à l'aide de files d'attente

Dans cet article, nous allons explorer l'API Queue dans le framework Web Laravel. Il vous permet de différer des tâches gourmandes en ressources lors de l'exécution de script afin d'améliorer l'expérience globale de l'utilisateur final. Après avoir introduit la terminologie de base, je vais vous la démontrer en implémentant un exemple concret.

Le temps de chargement des pages est un aspect important de tout site Web performant, et il ne faut pas négliger son importance, car elle a également une incidence sur le référencement du site et sur l'expérience globale de l'utilisateur final. Plus souvent qu'autrement, vous finissez par avoir besoin de déboguer des pages Web avec des temps de chargement de page longs. Bien sûr, vous pouvez utiliser différentes approches pour remédier à ce problème..

Après enquête, vous réalisez souvent que certains blocs de code entraînent un retard dans l'exécution de la page. La prochaine chose que vous pouvez essayer est d’identifier les blocs qui peuvent être différés pour le traitement et qui n’ont pas d’impact réel sur le résultat final de la page en cours. Cela devrait vraiment améliorer la vitesse globale de la page Web, car nous avons éliminé les blocs de code à l'origine du retard..

Aujourd'hui, nous allons explorer un concept similaire dans le contexte du framework Web Laravel. En fait, Laravel fournit déjà une API intégrée très utile qui nous permet de différer le traitement des tâches, l’API de file d’attente. Sans perdre beaucoup de votre temps, je vais aller de l'avant et discuter des éléments de base de l'API de file d'attente.

Pilotes, connexions, files d'attente et travaux

L'objectif fondamental de l'API Queue est d'exécuter des travaux ajoutés dans une file d'attente. Ensuite, la file d'attente peut appartenir à une connexion spécifique et cette connexion peut appartenir à un pilote de file d'attente spécifique configuré avec cette connexion elle-même. Essayons brièvement de comprendre ce que je viens de dire.

Pilotes de file d'attente

De la même manière que vous auriez utilisé un pilote différent pour votre connexion de base de données, vous pouvez également choisir parmi une variété de pilotes de file d’attente différents. L'API de file d'attente prend en charge différents adaptateurs tels que base de données, beanstalkd, sqs et redis..

Le pilote de file d'attente est simplement un emplacement utilisé pour stocker des informations relatives à la file d'attente. Ainsi, si vous utilisez un pilote de file d'attente de base de données, par exemple, le nouveau travail sera ajouté à la table des travaux de la base de données. Par ailleurs, si vous avez configuré Redis en tant que pilote de file d'attente par défaut, le travail sera ajouté au serveur Redis..

L'API de file d'attente fournit également deux pilotes de file d'attente spéciaux pour le test de fins-sync et null. Le pilote de la file d'attente de synchronisation est utilisé pour exécuter un travail en file d'attente immédiatement, tandis que le pilote de la file d'attente nulle est utilisé pour ignorer un travail afin qu'il ne soit pas exécuté du tout..

Les liaisons

Lorsque vous configurez l'API de file d'attente pour la première fois, vous devez spécifier une connexion par défaut à utiliser pour le traitement de la file d'attente par défaut. À tout le moins, la connexion devrait fournir les informations suivantes:

  • le pilote de file d'attente qui sera utilisé
  • les valeurs de configuration spécifiques du pilote de file d'attente
  • le nom de la file d'attente par défaut dans lequel le travail sera ajouté

Les files d'attente

Lorsque vous ajoutez un travail dans une file d'attente, il sera ajouté à la file d'attente par défaut. En fait, cela devrait aller dans la plupart des cas, à moins que vous n'ayez des emplois qui nécessitent une priorité plus élevée que les autres. Dans ce cas, vous pouvez créer une file d'attente nommée haute et placez les travaux les plus prioritaires dans cette file d'attente.

Lorsque vous exécutez un programme de traitement de file d'attente traitant des travaux en file d'attente, vous pouvez éventuellement transmettre le --queue Ce paramètre vous permet de répertorier les noms des files d'attente dans l'ordre dans lequel elles doivent être traitées. Par exemple, si vous spécifiez --queue = haute, par défaut, il va d'abord traiter les emplois dans le haute file d'attente, et une fois terminée, elle récupère les travaux dans la file d'attente par défaut.

Emplois

Un travail dans l'API de file d'attente est une tâche différée du flux d'exécution principal. Par exemple, si vous souhaitez créer une vignette lorsque l'utilisateur télécharge une image à partir du serveur frontal, vous pouvez créer un nouveau travail qui gère le traitement des vignettes. De cette manière, vous pouvez différer la tâche du traitement des vignettes du flux d’exécution principal..

C'était une introduction de base à la terminologie de l'API de file d'attente. À partir de la section suivante, nous verrons comment créer un travail de file d'attente personnalisé et l'exécuter à l'aide d'un programme de travail de file d'attente Laravel..

Créez votre premier travail en file d'attente

A présent, vous devriez avoir confiance en vos tâches en file d'attente. À partir de cette section, nous allons implémenter un exemple concret illustrant le concept de travail en file d'attente dans Laravel..

Le plus souvent, vous vous retrouvez dans la situation où vous devez créer différentes versions miniatures d'une image téléchargée par un utilisateur. Dans la plupart des cas, le développeur essaie de le traiter en temps réel afin que différentes versions des images soient créées immédiatement lorsque l'utilisateur télécharge une image..

Cela semble être une approche raisonnable si vous voulez créer deux versions et cela ne prend pas trop de temps au départ. D'autre part, si vous traitez avec une application qui nécessite un traitement lourd et consomme donc plus de ressources, le traitement en temps réel pourrait aboutir à une mauvaise expérience utilisateur..

L'option évidente qui vous vient à l'esprit est de différer le traitement de la génération de vignettes le plus tard possible. L'approche la plus simple que vous pouvez implémenter dans ce scénario spécifique consiste à définir un travail cron qui déclenche le traitement à intervalles réguliers, et tout devrait bien se passer..

Une approche bien meilleure, en revanche, consiste à différer la tâche et à la placer dans une file d’attente, et à laisser le responsable du traitement de la file d’attente la traiter quand elle en aura l’occasion. Dans un environnement de production, l’ouvrier de file d’attente est un script démon qui exécute et traite en permanence les tâches d’une file. L'avantage évident de cette approche est une expérience utilisateur bien meilleure, et vous n'avez pas à attendre l'exécution de cron car le travail sera traité dès que possible..

Je suppose que c'est assez de théorie pour démarrer avec une implémentation réelle.

Dans notre cas, nous allons utiliser le base de données pilote de file d'attente, et il nous oblige à créer le emplois table dans la base de données. le emplois table contient toutes les tâches devant être traitées lors de la prochaine exécution du programme de traitement des files d'attente.

Avant de continuer et de créer le emplois table, changeons la configuration de la file d'attente par défaut de synchroniser à base de données dans le config / queue.php fichier.

… / * | -------------------------------------------------- ---------------------------- | Pilote de file d'attente par défaut | -------------------------------------------------- ---------------------------- | | L'API de file d'attente de Laravel prend en charge un assortiment de back-end via un seul | API, vous donnant un accès pratique à chaque back-end en utilisant le même | syntaxe pour chacun. Ici, vous pouvez définir le pilote de file d'attente par défaut. | | Pris en charge: "sync", "base de données", "beanstalkd", "sqs", "redis", "null" | * / 'default' => env ('QUEUE_DRIVER', 'database'),… 

En fait, Laravel fournit déjà une commande artisanale qui nous aide à créer le emplois table. Exécutez la commande suivante à la racine de votre application Laravel. Elle devrait créer la migration de base de données nécessaire créant le emplois table.

$ php artisan file: table

Le fichier de migration généré à base de données / migrations / YYYY_MM_DD_HHMMSS_create_jobs_table.php devrait ressembler à ceci:

bigIncrements ('id'); $ table-> string ('queue'); $ table-> longText ('charge utile'); $ table-> unsignedTinyInteger ('tentatives'); $ table-> unsignedInteger ('reserved_at') -> nullable (); $ table-> unsignedInteger ('available_at'); $ table-> unsignedInteger ('created_at'); $ table-> index (['queue', 'reserved_at']); );  / ** * Inverser les migrations. * * @return void * / public function down () Schema :: dropIfExists ('jobs');  

Ensuite, exécutons le émigrer commande afin qu'il crée réellement la emplois table dans une base de données.

php artisan migrer

C'est tout ce que le emplois la migration est concernée.

Ensuite, créons le Image modèle qui sera utilisé pour gérer les images téléchargées par l'utilisateur final. Le modèle d'image requiert également une table de base de données associée. Nous allons donc utiliser le --émigrer option lors de la création du Image modèle.

fabrication artisanale php: model Image --migration

La commande ci-dessus devrait créer le Image classe de modèle et une migration de base de données associée, ainsi.

le Image La classe modèle devrait ressembler à ceci:

Et le fichier de migration de base de données doit être créé à base de données / migrations / YYYY_MM_DD_HHMMSS_create_images_table.php. Nous souhaitons également stocker le chemin d'origine de l'image téléchargée par l'utilisateur final. Révisons le code de la Image fichier de migration de base de données pour ressembler à ce qui suit.

incréments ('id'); $ table-> horodatages (); $ table-> string ('org_path'); );  / ** * Inverser les migrations. * * @return void * / public function down () Schema :: dropIfExists ('images'); 

Comme vous pouvez le voir, nous avons ajouté le $ table-> string ('org_path') colonne pour stocker le chemin de l'image d'origine. Ensuite, il vous suffit de lancer le émigrer commande pour créer réellement cette table dans la base de données.

$ php artisan migrate

Et c'est tout aussi loin que le Image le modèle est concerné.

Ensuite, créons un travail de file d'attente réel chargé du traitement des vignettes d'image. Pour le traitement des vignettes, nous allons utiliser une bibliothèque de traitement d’images très populaire: Intervention Image..

Pour installer la bibliothèque d'images d'intervention, continuez et exécutez la commande suivante à la racine de votre application..

$ php composer.phar nécessite une intervention / image

Maintenant, il est temps de créer le Emploi classe, et nous allons utiliser une commande artisanale pour le faire.

$ php fabrication artisanale: job ProcessImageThumbnails

Cela devrait créer le Emploi modèle de classe à app / Jobs / ProcessImageThumbnails.php. Remplaçons le contenu de ce fichier par le suivant.

image = $ image;  / ** * Exécuter le travail. * * @return void * / public function handle () // accéder au modèle dans la file d'attente pour le traitement de $ image = $ this-> image; $ full_image_path = chemin_public ($ image-> chemin_org); $ resized_image_path = public_path ('thumbs'. DIRECTORY_SEPARATOR. $ image-> org_path); // crée des vignettes à partir de l'image d'origine $ img = \ Image :: make ($ chemin_image_présente) -> resize (300, 200); $ img-> save ($ resized_image_path); 

Lorsque le travailleur de la file commence à traiter un travail, il recherche le manipuler méthode. Donc c'est le manipuler méthode qui détient la logique principale de votre travail.

Dans notre cas, nous devons créer une vignette d'une image téléchargée par l'utilisateur. Le code de la manipuler méthode est assez simple, nous récupérons une image de la ImageModel modéliser et créer une vignette à l’aide de la bibliothèque d’intervention. Bien sûr, nous devons passer le correspondant Image modèle lorsque nous envoyons notre travail, et nous le verrons dans un instant.

Pour tester notre travail nouvellement créé, nous allons créer un formulaire de téléchargement simple permettant à l'utilisateur de télécharger une image. Bien sûr, nous ne créerons pas de vignettes d’images tout de suite; nous allons reporter cette tâche afin qu'elle puisse être traitée par le travailleur de la file d'attente.

Créons un fichier de contrôleur à app / Http / Controllers / ImageController.php comme indiqué ci-dessous.

validate ($ request, ['demo_image' => 'requis | 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']); // crée une entrée de base de données de cette image $ image = new Image; $ image-> org_path = 'images'. DIRECTORY_SEPARATOR. $ input ['demo_image']; $ image-> save (); // diffère le traitement des vignettes d'image ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> avec ('message', 'Image envoyée avec succès!'); 

Créons un fichier de vue associé sur resources / views / upload_form.blade.php.

       Laravel       
@if (Route :: has ('login'))
@if (Auth :: check ()) Accueil @else Connexion Inscrivez-vous @endif
@fin si

Formulaire d'envoi de démo

@if ($ errors-> any ())
    @foreach ($ errors-> all () as $ error)
  • $ error
  • @endforeach
@endif @if (session ('message'))
session ('message')
@fin si

Enfin, ajoutons des itinéraires pour le indice et télécharger actions dans le routes / web.php fichier.

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

dans le ImageController contrôleur, le indice méthode est utilisée pour rendre un formulaire de téléchargement.

index de fonction publique (Request $ request) return view ('upload_form'); 

Lorsque l'utilisateur soumet un formulaire, le télécharger la méthode est invoquée.

fonction publique upload (Request $ request) // upload image $ this-> 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']); // crée une entrée de base de données de cette image $ image = new Image; $ image-> org_path = 'images'. DIRECTORY_SEPARATOR. $ input ['demo_image']; $ image-> save (); // diffère le traitement des vignettes d'image ProcessImageThumbnails :: dispatch ($ image); return Redirect :: to ('image / index') -> avec ('message', 'Image envoyée avec succès!'); 

Au début de la télécharger méthode, vous remarquerez le code de téléchargement de fichier habituel qui déplace le fichier téléchargé vers le public / images annuaire. Ensuite, nous insérons un enregistrement de base de données en utilisant le App / Image modèle.

Enfin, nous utilisons le ProcessImageThumbnails tâche pour différer la tâche de traitement des vignettes. Il est important de noter que c'est le envoi méthode qui est utilisée pour reporter une tâche. À la fin, l'utilisateur est redirigé vers la page de téléchargement avec un message de réussite..

À ce stade, le travail est ajouté à la liste. emplois table pour le traitement. Confirmons-le en émettant la requête suivante.

mysql> select * FROM lvl_jobs; | 1 | par défaut | "displayName": "App \\ Jobs \\ ProcessImageThumbnails", "job": "Illuminate \\ File d'attente \\ CallQueuedHandler @ call", "maxTries": null, "délai d'attente": null, "data": "commandName ":" App \\ Jobs \\ ProcessImageThumbnails "," commande ":" O: 31: \ "App \\ Jobs \\ ProcessImageThumbnails \": 5: s: 8: \ "\ u0000 * \ u0000image \"; O: 45: \ "Illuminer \\ Contrats \\ Base de données \\ Identificateur de modèle \": 2: s: 5: \ "class \"; s: 9: \ "App \\ Image \"; s: 2: \ "id \"; i: 2; s: 6: \ "\ u0000 * \ u0000job \"; N; s: 10: \ "connexion \"; N; s: 5: \ "file d'attente" "; N; s: 5: \ "delay \"; N; " | 0 | NULL | 1510219099 | 1510219099 |

Vous devez vous demander, que faut-il pour traiter un travail alors? Ne vous inquiétez pas, c'est ce dont nous allons discuter dans la section suivante..

Travailleur en file d'attente

Le travail du gestionnaire de file d'attente Laravel consiste à traiter les travaux mis en file d'attente pour traitement. En fait, une commande artisanale nous aide à démarrer le processus de traitement de la file d'attente.

$ php artisan queue: travail

Dès que vous exécutez cette commande, les tâches en attente sont traitées. Dans notre cas, il devrait traiter le ProcessImageThumbnails travail mis en file d'attente lorsque l'utilisateur a téléchargé une image plus tôt.

File d'attente artisanale $ php: travail [AAAA-MM-JJ HHMMSS] Traitement: App \ Jobs \ ProcessImageThumbnails [AAAA-MM-JJ HHMMSS] Traitement: App \ Jobs \ ProcessImageThumbnails

Vous auriez remarqué que lorsque vous démarrez un ouvrier de file d'attente, celui-ci continue à fonctionner jusqu'à ce que vous le supprimiez manuellement ou fermiez le terminal. En fait, il attend que le prochain travail soit traité. Dès qu'un nouveau travail est en file d'attente, il est immédiatement traité si le programme de travail en file d'attente est en cours d'exécution..

Bien sûr, nous ne pouvons pas continuer à le faire de cette manière, nous devons donc trouver un moyen pour que le système de traitement des files d'attente s'exécute en permanence en arrière-plan..

À notre secours, il existe plusieurs outils de gestion de processus parmi lesquels vous pouvez choisir. Pour en nommer quelques-uns, voici une liste:

  • Cirque
  • Daemon Tools
  • Monit
  • Superviseur
  • Parvenu

Vous devez choisir un outil avec lequel vous êtes à l'aise pour gérer le travailleur de la file d'attente Laravel. En gros, nous voulons nous assurer que le programme de traitement de file d'attente doit s'exécuter indéfiniment afin de pouvoir traiter immédiatement les travaux en file d'attente..

Voilà donc l'API de file d'attente à votre disposition. Vous pouvez l'utiliser dans votre développement quotidien pour différer des tâches fastidieuses afin d'améliorer l'expérience de l'utilisateur final..

Conclusion

Dans cet article, nous avons discuté de l’API de file d’attente dans Laravel, ce qui est très utile si vous souhaitez différer le traitement des tâches gourmandes en ressources..

Nous avons commencé par une introduction de base à l'API Queue, qui impliquait une discussion sur les connexions, les files d'attente et les travaux. Dans la seconde moitié de l'article, nous avons créé un travail de file d'attente personnalisé qui montrait comment utiliser l'API de file d'attente dans le monde réel..

Pour ceux d'entre vous qui débutent avec Laravel ou qui souhaitent développer leurs connaissances, leur site ou leur application avec des extensions, nous pouvons étudier de nombreuses choses sur le marché Envato..

N'hésitez pas à utiliser le formulaire de commentaires ci-dessous pour poster vos questions et suggestions..