Shell asynchrone exec en PHP
j'ai un script PHP qui doit invoquer un script shell mais qui ne se soucie pas du tout de la sortie. Le script shell fait un certain nombre d'appels SOAP et est lent à compléter, donc je ne veux pas ralentir la requête PHP pendant qu'elle attend une réponse. En fait, la requête PHP devrait être capable de quitter sans terminer le processus 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?
13 réponses
S'il" ne se soucie pas de la sortie", ne pourrait-on pas appeler l'exec du script avec le &
pour background le processus?
MODIFIER - en intégrant ce @ AdamTheHut , a commenté à ce post, vous pouvez l'ajouter à un appel à exec
:
" > /dev/null 2>/dev/null &"
qui redirigera à la fois stdio
(premier >
) et stderr
( 2>
) vers /dev/null
et lancera 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 &"
j'ai utilisé à pour ceci, car il commence vraiment un processus indépendant.
<?php
`echo "the command"|at now`;
?>
sur linux vous pouvez faire ce qui suit:
$cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = shell_exec($cmd);
ceci exécutera la commande à la commande prompty et ensuite juste retourner le PID, que vous pouvez vérifier pour > 0 pour s'assurer qu'il a fonctionné.
cette question est similaire: PHP a-t-il un threading?
pour tous les utilisateurs de Windows: j'ai trouvé un bon moyen d'exécuter un script PHP asynchrone (en fait il fonctionne avec presque tout).
est basé sur les commandes popen() et pclose (). Et fonctionne bien sous Windows et Unix.
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
code Original de: http://php.net/manual/en/function.exec.php#86329
php-executer-un-fond-processus a quelques bonnes suggestions. Je pense que le mien est assez bonne, mais je suis partial :)
sous Linux, vous pouvez démarrer un processus dans un nouveau thread indépendant en ajoutant un ampli à la fin de la commande
mycommand -someparam somevalue &
sous Windows, vous pouvez utiliser la commande" start "DOS
start mycommand -someparam somevalue
le droit chemin(!) c'est de
- fork ()
- setsid ()
- execve ()
fourchettes, setsid dire au processus en cours de devenir un maître Un (aucun parent), execve dire au processus appelant d'être remplacé par le appelé. pour que le parent puisse cesser de fumer sans nuire à l'enfant.
$pid=pcntl_fork();
if($pid==0)
{
posix_setsid();
pcntl_exec($cmd,$args,$_ENV);
// child becomes the standalone detached process
}
// parent's stuff
exit();
j'ai utilisé ceci...
/**
* Asynchronously execute/include a PHP file. Does not record the output of the file anywhere.
* Relies on the PHP_PATH config constant.
*
* @param string $filename file to execute
* @param string $options (optional) arguments to pass to file via the command line
*/
function asyncInclude($filename, $options = '') {
exec(PHP_PATH . " -f {$filename} {$options} >> /dev/null &");
}
(où PHP_PATH
est un const défini comme define('PHP_PATH', '/opt/bin/php5')
ou similaire)
il passe en arguments via la ligne de commande. Pour les lire en PHP, voir argv .
la seule façon que j'ai trouvé qui a vraiment travaillé pour moi était:
shell_exec('./myscript.php | at now & disown')
j'ai aussi trouvé Symfony Processus de la Composante utile pour cela.
use Symfony\Component\Process\Process;
$process = new Process('ls -lsa');
// ... run process in background
$process->start();
// ... do other things
// ... if you need to wait
$process->wait();
// ... do things after the process has finished
Voir comment cela fonctionne dans son dépôt GitHub .
utilisez un fifo nommé.
#!/bin/sh
mkfifo trigger
while true; do
read < trigger
long_running_task
done
ensuite, chaque fois que vous voulez lancer la tâche longue exécution, il vous suffit d'écrire une nouvelle ligne (non bloquante dans le fichier de déclenchement).
aussi longtemps que votre entrée est plus petite que PIPE_BUF
et que c'est une seule opération write()
, vous pouvez écrire des arguments dans le fifo et les faire apparaître comme $REPLY
dans le script.
vous pouvez également exécuter le script PHP comme démon ou cronjob : #!/usr/bin/php -q
sans file d'attente d'utilisation, vous pouvez utiliser le proc_open()
comme ceci:
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w") //here curaengine log all the info into stderror
);
$command = 'ping stackoverflow.com';
$process = proc_open($command, $descriptorspec, $pipes);