web-dev-qa-db-fra.com

PHP Processus d'arrière-plan

J'essaie de faire un script PHP, j'ai terminé le script mais cela prend environ 10 minutes pour terminer le processus pour lequel il est conçu. Ce n'est pas un problème, mais je suppose que je dois garder la page chargée pendant tout ce temps, ce qui est ennuyeux. Puis-je l'avoir pour démarrer le processus, puis revenir 10 minutes plus tard et afficher le fichier journal qu'il a généré?

41
zuk1

Eh bien, vous pouvez utiliser " ignore_user_abort (true)"

Le script continuera donc de fonctionner (gardez un œil sur la durée du script, ajoutez peut-être " set_time_limit (0)")

Mais un avertissement ici: vous ne pourrez pas arrêter un script avec ces deux lignes:

ignore_user_abort(true); 
set_time_limit(0);

Sauf que vous pouvez accéder directement au serveur et y tuer le processus! (J'y suis allé, fait une boucle sans fin, s'appelant sans cesse, a fait arrêter le serveur de hurlements, s'est fait crier dessus ...)

50
bastiandoeen

On dirait que vous devriez avoir une file d'attente et un script externe pour traiter la file d'attente.

Par exemple, votre script PHP doit placer une entrée dans une table de base de données et revenir immédiatement. Ensuite, un cron exécuté toutes les minutes vérifie la file d'attente et lance un processus pour chaque travail.

L'avantage ici est que vous ne verrouillez pas un thread Apache pendant 10 minutes.

26
Gary Richardson

J'ai eu beaucoup de problèmes avec ce genre de processus sous Windows; Ma situation était un peu différente en ce que je ne me souciais pas de la réponse du "script" - je voulais que le script démarre et permette aux autres demandes de page de passer pendant qu'il était occupé à travailler.

Pour certaines raisons; J'ai eu des problèmes avec le fait de suspendre d'autres requêtes ou de temporiser après environ 60 secondes (Apache et php ont tous deux été définis pour expirer après environ 20 minutes); Il s'avère également que firefox expire après 5 minutes (par défaut) de toute façon, après ce point, vous ne pouvez pas savoir ce qui se passe via le navigateur sans modifier les paramètres de firefox.

J'ai fini par utiliser les méthodes d'ouverture et de fermeture des processus pour ouvrir un php en mode cli comme suit:

pclose(popen("start php myscript.php", "r"));

Cela (en utilisant start) ouvrirait le processus php, puis tuerait le processus de démarrage, laissant php en cours d'exécution aussi longtemps qu'il le faudrait - encore une fois, vous devrez tuer le processus pour l'arrêter manuellement. Il n'a pas eu besoin de vous pour définir des délais d'expiration et vous pouvez laisser la page actuelle qui l'a appelée continuer et afficher plus de détails.

Le seul problème avec cela est que si vous avez besoin d'envoyer des données au script, vous devez soit le faire via une autre source ou le transmettre le long de la "ligne de commande" en tant que paramètres; ce qui n'est pas si sûr.

A bien fonctionné pour ce dont nous avions besoin et garantit que le script démarre toujours et peut s'exécuter sans interruption.

8

Cela peut également être utile: Exécution du shell asynchrone en PHP

6
warren

Je pense que la commande Shell_exec est ce que vous recherchez.

Cependant, il est désactivé en mode sans échec.

L'article PHP manuel à ce sujet est ici: http://php.net/Shell_exec

Il y a un article à ce sujet ici: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

5
Jon

Il existe une autre option que vous pouvez utiliser, exécutez le script CLI ... Il s'exécutera en arrière-plan et vous pouvez même l'exécuter en tant que cronjob si vous le souhaitez.

par exemple

> #!/usr/bin/php -q

<?php

//process logs

?>

Cela peut être configuré comme un cronjob et s'exécutera sans limitation de temps .... cet exemple est cependant pour le système d'exploitation basé sur unix.

Pour info j'ai un script php fonctionnant avec une boucle infinie qui fait un peu de traitement et qui fonctionne depuis 3 mois sans arrêt.

4
Ronald Conco

Vous pouvez utiliser ignore_user_abort() - de cette façon, le script continuera à s'exécuter même si vous fermez votre navigateur ou accédez à une autre page.

3
Greg

En plus de la réponse de bastiandoeen, vous pouvez combiner ignore_user_abort(true); avec une requête cUrl .

Faux une demande d'avortement définissant un faible CURLOPT_TIMEOUT_MS et continuer le traitement après la fermeture de la connexion:

function async_curl($background_process=''){

    //-------------get curl contents----------------

    $ch = curl_init($background_process);
    curl_setopt_array($ch, array(
        CURLOPT_HEADER => 0,
        CURLOPT_RETURNTRANSFER =>true,
        CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
        CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
        CURLOPT_VERBOSE => 1,
        CURLOPT_HEADER => 1
    ));
    $out = curl_exec($ch);

    //-------------parse curl contents----------------

    //$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    //$header = substr($out, 0, $header_size);
    //$body = substr($out, $header_size);

    curl_close($ch);

    return true;
}

async_curl('http://example.com/background_process_1.php');

[~ # ~] nb [~ # ~]

Si vous voulez que cURL expire en moins d'une seconde, vous pouvez utiliser CURLOPT_TIMEOUT_MS, bien qu'il y ait un bogue/"fonctionnalité" sur "les systèmes de type Unix" qui fait que libcurl expire immédiatement si la valeur est <1000 ms avec l'erreur " Erreur cURL (28): le délai a été atteint ". L'explication de ce comportement est:

[...]

La solution consiste à désactiver les signaux à l'aide de CURLOPT_NOSIGNAL

pros

  • Pas besoin de changer de méthode (Windows et Linux compatibles)
  • Pas besoin d'implémenter la gestion des connexions via les en-têtes et le tampon (indépendant du navigateur et PHP)

contre

  • Besoin d'une extension de boucle

Ressources

2
RafaSashi

Pensez à Gearman

Gearman est un cadre d'application générique pour la sous-traitance de plusieurs machines ou processus. Il permet aux applications d'effectuer des tâches en parallèle, d'équilibrer la charge de traitement et d'appeler des fonctions entre les langues. Le cadre peut être utilisé dans une variété d'applications, des sites Web à haute disponibilité au transport des événements de réplication de base de données.

Cette extension fournit des cours pour écrire des clients et des employés Gearman. - Manuel php source

Site officiel de Gearman

2
Gowri

Zuk.

Je suis sûr que cela fonctionnera:

<?php 

pclose(popen('php /path/to/file/server.php &'));
echo "Server started. [OK]"; 

?>

Le '&' est important. Il indique au Shell de ne pas attendre la fin du processus.

Vous pouvez également utiliser ce code dans votre php (comme l'a dit "bastiandoeen")

ignore_user_abort(true); 
set_time_limit(0);

dans la commande d'arrêt de votre serveur:

<?php

$output;
exec('ps aux | grep -ie /path/to/file/server.php | awk \'{print $2}\' | xargs kill -9 ', $output);
    echo "Server stopped. [OK]";

?>
1
Nader