Je travaille sur une application web assez volumineuse, et le backend est principalement en PHP. Il y a plusieurs endroits dans le code où je dois effectuer une tâche, mais je ne veux pas que l'utilisateur attende le résultat. Par exemple, lors de la création d'un nouveau compte, je dois leur envoyer un e-mail de bienvenue. Mais quand ils cliquent sur le bouton «Terminer l'enregistrement», je ne veux pas les faire attendre jusqu'à ce que l'e-mail soit réellement envoyé, je veux juste démarrer le processus et renvoyer un message à l'utilisateur tout de suite.
Jusqu'à présent, dans certains endroits, j'ai utilisé ce qui ressemble à un hack avec exec (). En gros, faire des choses comme:
exec("doTask.php $arg1 $arg2 $arg3 >/dev/null 2>&1 &");
Ce qui semble fonctionner, mais je me demande s'il existe un meilleur moyen. J'envisage d'écrire un système qui met en file d'attente les tâches dans une table MySQL, et un script PHP séparé de longue durée qui interroge cette table une fois par seconde et exécute toutes les nouvelles tâches qu'il trouve. Cela aurait également l'avantage de me permettre de répartir les tâches entre plusieurs machines de travail à l'avenir si j'en avais besoin.
Est-ce que je réinvente la roue? Existe-t-il une meilleure solution que le hack exec () ou la file d'attente MySQL?
Lorsque vous souhaitez simplement exécuter une ou plusieurs requêtes HTTP sans avoir à attendre la réponse, il existe également une solution PHP simple.
Dans le script d'appel:
Sur le script.php appelé, vous pouvez invoquer ces fonctions PHP dans les premières lignes:
Cela provoque l'exécution du script sans limite de temps lorsque la connexion HTTP est fermée.
la source
Une autre façon de bifurquer les processus est via curl. Vous pouvez configurer vos tâches internes en tant que service Web. Par exemple:
Ensuite, dans vos scripts accédés par l'utilisateur, appelez le service:
Votre service peut garder une trace de la file d'attente des tâches avec mysql ou tout ce que vous voulez: tout est enveloppé dans le service et votre script ne consomme que des URL. Cela vous permet de déplacer le service vers une autre machine / serveur si nécessaire (c'est-à-dire facilement évolutif).
L'ajout d'une autorisation http ou d'un schéma d'autorisation personnalisé (comme les services Web d'Amazon) vous permet d'ouvrir vos tâches à d'autres personnes / services (si vous le souhaitez) et vous pouvez aller plus loin et ajouter un service de surveillance en plus pour garder une trace de état de la file d'attente et de la tâche.
Cela prend un peu de travail de configuration, mais il y a beaucoup d'avantages.
la source
J'ai utilisé Beanstalkd pour un projet et je prévoyais de recommencer. J'ai trouvé que c'était un excellent moyen d'exécuter des processus asynchrones.
J'ai fait quelques choses avec:
J'ai écrit un système basé sur Zend-Framework pour décoder une URL «sympa», par exemple pour redimensionner une image qu'il appellerait
QueueTask('/image/resize/filename/example.jpg')
. L'URL a d'abord été décodée en un tableau (module, contrôleur, action, paramètres), puis convertie en JSON pour être injectée dans la file d'attente elle-même.Un script cli de longue durée a ensuite récupéré le travail dans la file d'attente, l'a exécuté (via Zend_Router_Simple) et, si nécessaire, mis des informations dans memcached pour que le site Web PHP les récupère lorsque cela a été fait.
Une difficulté que j'ai également ajoutée était que le cli-script ne fonctionnait que pendant 50 boucles avant de redémarrer, mais s'il voulait redémarrer comme prévu, il le ferait immédiatement (exécuté via un script bash). S'il y avait un problème et que je l'ai fait
exit(0)
(la valeur par défaut pourexit;
oudie();
), cela ferait d'abord une pause pendant quelques secondes.la source
S'il s'agit simplement de fournir des tâches coûteuses, dans le cas où php-fpm est pris en charge, pourquoi ne pas utiliser la
fastcgi_finish_request()
fonction?Vous n'utilisez pas vraiment l'asynchronicité de cette manière:
fastcgi_finish_request()
.Une fois de plus, php-fpm est nécessaire.
la source
Voici une classe simple que j'ai codée pour mon application Web. Il permet de forger des scripts PHP et d'autres scripts. Fonctionne sous UNIX et Windows.
la source
C'est la même méthode que j'utilise depuis quelques années maintenant et je n'ai rien vu ni trouvé de mieux. Comme les gens l'ont dit, PHP est monothread, donc vous ne pouvez pas faire grand-chose d'autre.
J'ai en fait ajouté un niveau supplémentaire à cela et c'est obtenir et stocker l'ID de processus. Cela me permet de rediriger vers une autre page et de faire asseoir l'utilisateur sur cette page, en utilisant AJAX pour vérifier si le processus est terminé (l'identifiant de processus n'existe plus). Ceci est utile dans les cas où la longueur du script entraînerait l'expiration du délai du navigateur, mais l'utilisateur doit attendre que ce script se termine avant l'étape suivante. (Dans mon cas, il traitait de gros fichiers ZIP avec des fichiers de type CSV qui ajoutent jusqu'à 30000 enregistrements à la base de données, après quoi l'utilisateur doit confirmer certaines informations.)
J'ai également utilisé un processus similaire pour la génération de rapports. Je ne suis pas sûr que j'utiliserais le "traitement en arrière-plan" pour quelque chose comme un e-mail, à moins qu'il y ait un réel problème avec un SMTP lent. Au lieu de cela, je pourrais utiliser une table comme file d'attente, puis avoir un processus qui s'exécute toutes les minutes pour envoyer les e-mails dans la file d'attente. Vous devez être prudent d’envoyer des courriels deux fois ou d’autres problèmes similaires. J'envisagerais également un processus de mise en file d'attente similaire pour d'autres tâches.
la source
PHP HAS multithreading, il n'est tout simplement pas activé par défaut, il existe une extension appelée pthreads qui fait exactement cela. Cependant, vous aurez besoin de php compilé avec ZTS. (Thread Safe) Liens:
Exemples
Un autre tutoriel
Extension de pthreads PECL
la source
C'est une bonne idée d'utiliser cURL comme suggéré par rojoca.
Voici un exemple. Vous pouvez surveiller text.txt pendant que le script s'exécute en arrière-plan:
la source
Malheureusement, PHP ne dispose d'aucune sorte de capacités de threading natives. Je pense donc que dans ce cas, vous n'avez pas d'autre choix que d'utiliser une sorte de code personnalisé pour faire ce que vous voulez faire.
Si vous recherchez sur le net des trucs de threads PHP, certaines personnes ont trouvé des moyens de simuler des threads sur PHP.
la source
Si vous définissez l'en-tête HTTP Content-Length dans votre réponse "Merci de votre inscription", le navigateur doit fermer la connexion une fois le nombre d'octets spécifié reçu. Cela laisse le processus côté serveur en cours d'exécution (en supposant que ignore_user_abort est défini) afin qu'il puisse finir de fonctionner sans faire attendre l'utilisateur final.
Bien sûr, vous devrez calculer la taille de votre contenu de réponse avant de rendre les en-têtes, mais c'est assez facile pour les réponses courtes (écrire la sortie dans une chaîne, appeler strlen (), appeler l'en-tête (), rendre la chaîne).
Cette approche a l’avantage de ne pas vous obliger à gérer une file d’attente «front-end», et bien que vous deviez peut-être faire un peu de travail sur le back-end pour éviter que les processus enfants HTTP ne se marchent les uns sur les autres, c'est quelque chose que vous deviez déjà faire , en tous cas.
la source
header('Content-Length: 3'); echo '1234'; sleep(5);
alors même si le navigateur ne prend que 3 caractères, il attend toujours 5 secondes avant d'afficher la réponse. Qu'est-ce que je rate?phpinfo()
. La seule autre chose que je pourrais imaginer est que je dois d'abord atteindre une taille de tampon minimum, par exemple 256 octets environ.Si vous ne voulez pas l'ActiveMQ à part entière, je vous recommande d'envisager RabbitMQ . RabbitMQ est une messagerie légère qui utilise la norme AMQP .
Je recommande de consulter également php-amqplib - une bibliothèque cliente AMQP populaire pour accéder aux courtiers de messages basés sur AMQP.
la source
Je pense que vous devriez essayer cette technique, cela vous aidera à appeler autant de pages que vous aimez toutes les pages fonctionneront à la fois indépendamment sans attendre que chaque page de réponse soit asynchrone.
cornjobpage.php // page principale
testpage.php
PS: si vous souhaitez envoyer des paramètres d'url en boucle, suivez cette réponse: https://stackoverflow.com/a/41225209/6295712
la source
Création de nouveaux processus sur le serveur en utilisant
exec()
ou directement sur un autre serveur utilisant curl ne s'adapte pas très bien du tout, si nous optons pour exec, vous remplissez essentiellement votre serveur de processus de longue durée qui peuvent être gérés par d'autres serveurs non Web, et l'utilisation de curl lie un autre serveur à moins que vous ne construisiez une sorte d'équilibrage de charge.J'ai utilisé Gearman dans quelques situations et je le trouve meilleur pour ce genre de cas d'utilisation. Je peux utiliser un serveur de file d'attente de travaux unique pour gérer la mise en file d'attente de tous les travaux devant être effectués par le serveur et faire tourner les serveurs de travail, chacun pouvant exécuter autant d'instances du processus de travail que nécessaire, et augmenter le nombre de les serveurs de travail selon les besoins et les ralentir lorsqu'ils ne sont pas nécessaires. Cela me permet également d'arrêter complètement les processus de travail lorsque cela est nécessaire et de mettre les travaux en file d'attente jusqu'à ce que les travailleurs reviennent en ligne.
la source
PHP est un langage à thread unique, il n'y a donc pas de moyen officiel de démarrer un processus asynchrone avec lui autre que d'utiliser
exec
oupopen
. Il y a un article de blog à ce sujet ici . Votre idée de file d'attente dans MySQL est également une bonne idée.Votre exigence spécifique ici est d'envoyer un e-mail à l'utilisateur. Je suis curieux de savoir pourquoi vous essayez de le faire de manière asynchrone, car l'envoi d'un e-mail est une tâche assez triviale et rapide à effectuer. Je suppose que si vous envoyez des tonnes de courriers électroniques et que votre FAI vous bloque en cas de suspicion de spam, cela pourrait être une raison de faire la queue, mais à part cela, je ne vois aucune raison de le faire de cette façon.
la source