Asynchrone shell exec de PHP
J'ai un script PHP qui doit invoquer un script shell, mais n'a pas de soins à la sortie. Le script shell fait un certain nombre d'appels SOAP et il est lent, donc je ne veux pas ralentir le PHP demande pendant qu'il attend une réponse. En effet, le PHP demande doit être en mesure de sortir sans arrêter le processus du shell.
J'ai regardé dans les différents exec()
, shell_exec()
, pcntl_fork()
, etc. fonctions, mais aucun d'entre eux semblent offrir exactement ce que je veux. (Ou, s'ils le font, ce n'est pas clair pour moi comment.) Des suggestions?
- N'importe quelle solution vous choisissez, vous devriez également envisager l'utilisation de
nice
etionice
pour éviter que le shell script à partir de submerger votre système (par exemple,/usr/bin/ionice -c3 /usr/bin/nice -n19
) - Double Possible de php d'exécuter un processus d'arrière-plan
Vous devez vous connecter pour publier un commentaire.
Si elle "ne se soucie pas de la sortie", ne pouvait pas le exec pour le script est appelé avec le
&
à fond le processus?MODIFIER - en intégrant ce @AdamTheHut commenté ce post, vous pouvez l'ajouter à un appel à
exec
:Qui va rediriger les deux
stdio
(première>
) etstderr
(2>
) à/dev/null
et exécuter en arrière-plan.Il y a d'autres façons de faire la même chose, mais c'est le plus simple à lire.
Une alternative à la double ci-dessus-redirect:
&> /dev/null &
, xdebug ne génère pas de journaux, si vous utilisez ce. Vérifier stackoverflow.com/questions/4883171/...<&- 1<&- 2<&-
<&- 1<&- 2<&-
faire? Je l'ai googlé, et je ne pouvais pas trouver une réponse./dev/null
est la meilleure pratique, comme l'écriture d'fermé FDs provoque des erreurs, alors que tente de lire ou d'écrire/dev/null
simplement en silence de ne rien faire.2>/dev/null >/dev/null
. Essayer de rediriger la sortie vers un fichier, par exemple, apache accrocher jusqu'à l'exécution terminée. Donc, mon approche a été de "pipe" la sortie detee
avant de la rediriger vers/dev/null
. Comme ceci:shell_exec('my_script.sh 2>&1 | tee -a mylog.log 2>/dev/null >/dev/null &');
~/log/mylog.log
au lieu de/dev/null
pour obtenir la sortie connectéJ'ai utilisé à pour cela, car c'est vraiment de départ d'un processus indépendant.
www-data
) n'a pas les autorisations pour utiliserat
et vous ne pouvez pas configurer, vous pouvez essayer d'utiliser<?php exec('sudo sh -c "echo \"command\" | at now" ');
Sicommand
contient des citations, voir escapeshellarg pour vous épargner les maux de têteecho "sudo command" | at now
et commentantwww-data
dans/etc/at.deny
À tous les utilisateurs de Windows: j'ai trouvé une bonne façon de gérer un asynchrones script PHP (en fait, il fonctionne avec presque tout).
Il est basé sur popen() et pclose() de commandes. Et fonctionne bien à la fois sur Windows et Unix.
Code d'origine à partir de: http://php.net/manual/en/function.exec.php#86329
Sur linux, vous pouvez effectuer les opérations suivantes:
Execute la commande à la commande prompty et puis il suffit de retourner le PID, que vous pouvez vérifier pour > 0 pour s'assurer qu'il a travaillé.
Cette question est similaire: N'PHP ont threading?
action=generate var1_id=23 var2_id=35 gen_id=535
segment). Aussi, depuis l'OP a demandé à propos de l'exécution d'un script shell, vous n'avez pas besoin de PHP-des portions spécifiques. La version finale du code serait:$cmd = 'nohup nice -n 10 /path/to/script.sh > /path/to/log/file.log & printf "%u" $!';
nice
mais aussiionice
.printf
est utilisé pour la sortie mise en forme de la$!
variable qui contient le PIDphp-executer-un-fond-processus a quelques bonnes suggestions. Je pense que le mien est assez bonne, mais je suis partial 🙂
Dans Linux, vous pouvez démarrer un processus dans un nouveau thread indépendant en ajoutant une esperluette à la fin de la commande
Dans Windows, vous pouvez utiliser le bouton "démarrer" de commande DOS
start
de commande sur windows, de ne pas exécuter de manière asynchrone... Pourriez-vous indiquer la source où vous avez obtenu cette information?/B
paramètre. Je l'ai expliqué ici: stackoverflow.com/a/34612967/1709903le droit chemin(!) c'est de
fourche fourche, setsid dire le processus actuel de devenir un maître à un (non parent), execve dire le processus appelant à être remplacé par l'appelé un. de sorte que le parent peut quitter sans affecter l'enfant.
J'ai utilisé ce...
(où
PHP_PATH
est un const défini commedefine('PHP_PATH', '/opt/bin/php5')
ou similaire)Il passe dans des arguments via la ligne de commande. De la lire en PHP, voir argv.
Le seul moyen que j'ai trouvé vraiment travaillé pour moi a été:
shell_exec("/usr/local/sbin/command.sh 2>&1 >/dev/null | at now & disown")
et tout ce que j'obtiens est:sh: 1: disown: not found
J'ai aussi trouvé Symfony Composant De Processus utile pour cela.
Voir comment cela fonctionne dans son Dépôt GitHub.
proc_*
fonctions internes.Utiliser un fichier fifo.
Alors à chaque fois que vous voulez commencer le long de la tâche en cours d'exécution, il suffit d'écrire un saut de ligne (non bloquant pour le déclenchement de fichier.
Tant que votre entrée est plus petite que
PIPE_BUF
et c'est un seulwrite()
opération, vous pouvez écrire des arguments dans la fifo et les faire apparaître comme$REPLY
dans le script.Vous pouvez également exécuter le script PHP en tant que démon ou tâche cron:
#!/usr/bin/php -q
sans utilisation de la file d'attente, vous pouvez utiliser le
proc_open()
comme ceci: