web-dev-qa-db-fra.com

Comment lancer un processus php asynchrone

Je développe un composant de commerce électronique.

J'ai remarqué que lorsque l'utilisateur effectue l'achat, le processus prend entre 18 et 20 secondes, ce qui est assez inacceptable.

Suite au code, j'ai constaté que l'envoi d'e-mails à l'aide de Joomla Mailer prend entre 1,8 et 2,4 secondes, et comme je dois envoyer plusieurs e-mails, cela explique pourquoi le processus est si long.

Existe-t-il un moyen d'envoyer des emails asynchrones?.

merci

2
Piero Marsilio

Il me semble que la question que vous posez n’est peut-être pas celle que vous vouliez poser (si je peux être aussi audacieux). Je suppose que la réponse 18-20s est inacceptable, soit parce que l'expérience utilisateur est mauvaise et/ou que c'est ennuyeux pour tout travail de type administrateur (peut-être entrepris par vous-même). Votre analyse du problème posé par l'envoi de courriers électroniques suggère que, en modifiant de manière significative, cela améliorera le symptôme principal - la réponse 18-20.

Alors, peut-être que votre question aurait dû être "Comment puis-je modifier le processus d'envoi du courrier afin qu'il ne bloque pas le reste du traitement?"

Les réponses possibles à à cette question varient selon que vous êtes auto-hébergeur/hébergement virtuel ou utilisez un serveur partagé. Avec la plupart des procédures d'envoi de courrier, les messages sont envoyés à un serveur SMTP pour être ensuite acheminés vers la ou les destination (s) finale (s). Notez que je fais la distinction entre l'envoi (ce que vous devez faire) et la livraison (ce que font les serveurs SMTP). Pour diverses raisons, les fournisseurs d’hébergement vous recommandent généralement d’envoyer des courriers via l’un ou l’autre de leurs serveurs - qui répondraient normalement beaucoup plus rapidement que le 1.8-2.4. s vous citez - les envois par courrier ne doivent durer que des dizaines ou des centaines de millisecondes.

Si vous pensez avoir les compétences, l'inclination et un accès complet au serveur, vous pouvez alors implémenter l'un des nombreux serveurs SMTP disponibles (pour les systèmes * nix, Postfix et Exim sont bons. options - pour Windows, vous pouvez essayer hMailServer ). Ensuite, ce serveur SMTP local traitera vos envois de courrier, les mettra en file d'attente, puis gérera la remise ultérieure de manière asynchrone. Bien entendu, cela se fait au détriment de la configuration et de la gestion de ces services (et en veillant à ne pas configurer par inadvertance un relais de messagerie ouvert (très mauvais)).

Si vous utilisez déjà le serveur de messagerie de votre fournisseur de services Internet (peut-être appelé "hôte intelligent") et que prend environ 2 secondes par courrier, vous devez vérifier si le La majeure partie de ce délai est liée à la manipulation de PHP avant sa soumission au serveur ou à son statut réel. Si vous avez un accès terminal à votre propre serveur, vous pouvez alors essayer de vous connecter telnet au serveur de messagerie du fournisseur de services Internet sur le port 25 et voir si le temps de réponse de la bannière prend un temps "long" (beaucoup de serveurs le font volontairement en raison du chargement). Voici un lien Microsoft expliquant comment effectuer de tels tests: article de MS Technet - Test telnet SMTP . Si le délai est long, je demanderais pourquoi au fournisseur de services Internet. Si la réponse n’est pas satisfaisante, vous devrez peut-être revenir au scénario serveur propre SMTP.

Incidemment, je suppose que vous utilisez BCC pour envoyer les mails, sinon vous pouvez normalement envoyer plusieurs adresses de messagerie avec un seul corps (BCC crée un corps par destinataire afin que chacun ne puisse pas voir les autres) - si BCC n’est pas requis, cela réduirait potentiellement le temps de réponse de N x 2 à 2 seulement, pour N destinataires. N est limité à environ 20, mais de nombreux facteurs déterminent ce que vous devez étudier dans votre environnement.

Si vous souhaitez vous en tenir à la question initiale sur les scripts asynchrones PHP, vous risquez de vous retrouver dans un chemin complexe, mais finalement sans issue. D'après ce que vous dites, je vous conseille vivement de vous assurer que vos envois de courrier sont rapides et mis en file d'attente dans un service "rapide" SMTP.

4
Mark Bradley

Vous ne pouvez pas exécuter de processus asynchrones PHP. Ce que vous pouvez faire est d’essayer d’utiliser un système de file d’attente. La tâche la plus simple consiste à exécuter un travail cron qui vérifie l’envoi de mailjobs. Ensuite, votre composant Il suffit de saisir les informations dans une table de base de données, puis le cron les récupère et crée les e-mails. Selon la fréquence à laquelle vous exécutez le cron, cela signifie évidemment un délai entre la commande et l'e-mail envoyé.

3
Bakual

Je suis d'accord avec @MarkBradley pour dire qu'il y a quelque chose d'étrange si l'envoi de courriels prend autant de temps. Cela dit, j'avais une obligation un peu liée d'envoyer un grand nombre de courriels en une seule requête Web (pas un logiciel de traitement de courrier en masse, mais un comportement similaire).

J'ai créé l'utilitaire de lancement de commandes async à usage général suivant pour PHP. Je suis sûr que cela pourrait faire avec un peu de polissage, mais cela sert au moins mon but:

function invokeAsyncCommand($p_command) {

    // Escape any single quotes in the command string before passing to Shell
    $command = str_replace("'", "'\"'\"'", $p_command);

    // Launch the command via an authorised user account using the 'at' command
    $command = "echo '$command' | Sudo -u somelimiteduser at now ";

    exec($command, $output, $return_var);

    return $return_var;
}

Notez l'utilisation de Sudo ici. Cela tient compte du fait que le compte d'utilisateur du serveur Web serait généralement configuré sans Shell et ne pourrait donc pas utiliser les commandes "at" ou associées. En outre, nous ne souhaitons pas donner au serveur Web un accès général à Shell. Nous l’autorisons donc à exécuter uniquement cette commande en tant qu’autre utilisateur disposant de privilèges limités (discussion ici ). Pour ce faire, ajoutez une ligne similaire à la suivante dans la configuration de votre sudoers (par exemple. visudo -f /etc/sudoers.d/mysudoers:

www-data        ALL = (somelimiteduser) NOPASSWD:/usr/bin/at

où www-data est le compte d'utilisateur du serveur Web.

Conseil : Soyez absolument certain que la valeur de $ p_command fournie ici ne contient aucun contenu fourni par l'utilisateur (c'est-à-dire qu'elle est entièrement générée dans votre propre code), ou est convenablement assaini avant utilisation!

Enfin, FWIW, j'ai créé un utilitaire Joomla CLI que j'appelle via la fonction ci-dessus pour effectuer ma tâche d'envoi en masse. Mon invocation de commande était donc dans les termes suivants:

invokeAsyncCommand(JPATH_BASE . '/cli/mycliutil.php --arg=someval');
1
John Rix