Faire tourner des scripts en tâche de fond - background

ViPHP
ViPHP | 1380 Messages

08 janv. 2006, 16:17

Parfois il est souhaitable de faire tourner des tâches/script en background pour des raisons de réactivité d'un site. Avant toute chose, il faut être conscient que si on lance un script en tâche de fond, il convient de s'assurer qu'il ne bouclera pas à l'infini! Car dans toutes les méthodes ci-dessous une fois que la tâche est lancée, plus moyen de l'arrêter! Prévoir donc un set_time_limit(nb sec.) adéquat.
  • Fonctions exec() ou passthru() disponibles

    Cas le plus simple: on lance le script en fond en invoquant directement un process sur le serveur (Linux, sur Windows, je crois que c'est également possible mais je ne peux tester. Quelqu'un?)
    exec ("/usr/local/bin/php /var/www/le_script.php > /dev/null&");
  • Fonctions exec() ou passthru() désactivées

    Situation courante chez beaucoup d'hébergeurs. Il faut alors travailler avec des sockets. Un script (parent) va servir de déclancheur. Il balance une requête HTTP vers le(s) script(s) à exécuter en arrière plan. Dès que l'entête http est partie, le script parent ferme la connexion. Le script appelé continuera à tourner car on aura pris soin d'y désactiver la possiblité pour le client (le script parent) d'arrêter l'exécution grâce à la fonction ignore_user_abort(). Ceci suppose, bien sûr, qu'on a le contrôle sur le script parent (voir plus loin, un cas particulier).
    // script parent = = = = = = = = = = = = = = = = = =
    
      // ici on stocke tous les scripts à lancer en tâche de fond
      $script = array(
        '/test/script_1.php',
        '/test/script_2.php'
      );
     
      $host = 'localhost';   // ou tout autre host cible 
    
      // ouverture des sockets (un par tâche à exécuter)
      foreach($script as $v){
        $fp = fsockopen($host, 80, $errno, $errstr, 10);
        stream_set_blocking ($fp, false);
        $header  = "GET $v HTTP /1.1\r\n";
        $header .= "User-Agent: monScriptPHP\r\n";
        $header .= "Connection: Close\r\n\r\n";
        fputs($fp, $header);
        fclose($fp);
      }
    
    // ici la suite du script. Affichage html, traitement php ou même header puisque le code ci-dessus n'envoie pas de header vers le navigateur client mais bien vers un script php.
    
    
    // script enfant (p. exple: script_1.php) = = = = = = = =
    
      ignore_user_abort(true);
    
      // ici ce qui doit être exécuté en tâche de fond
      // ici aussi attention à ne pas entrer dans une boucle infinie!
      // plus moyen de l'arrêter (sauf timeout serveur)
      // pour s'en protéger --> set_time_limit() 
    
    
    source: http://php.net/manual/fr/ref.exec.php#51094 (modifié car ne fonctionnera pas sans quelques aménagements)
  • Un script est lancé par un autre script sur lequel on a pas la main

    Cas particulier. Imaginez un site tiers qui vous envoie, par requête HTTP (post ou get), des données que vous devez traiter (calcul puis mise à jour fichiers ou dbb etc...). Votre script de mise à jour gardera la connexion ouverte avec le site tiers tant qu'il n'aura pas terminé le traitement. C'est ainsi que ces sites tiers (gateway SMS par exemple) se retrouvent avec des centaines de sockets ouverts. Ils n'aiment pas trop!

    Ce site tiers, ce sera peut-être vous un jour! :wink:

    Solution: leur envoyer un code 200 OK dès que les données POST ou GET sont récupérées. La suite du script continuera après la clôture de la connexion http.
    // récup des POST
    
       // ici code pour récupérer les POST/GET
    
    // envoi du header
    
       header("HTTP/1.1 200 OK");
    
    // Si une sortie sur le naviguateur client est nécessaire
    // il faut buffériser de la sortie
    
       ob_start();
    
      // ici tout code utile html et/ou php à afficher
    
       $size = ob_get_length();
       header("Content-Length: $size");
       ob_end_flush();
       flush();
    
    // à partir de maintenant, le client a reçu un 200 OK et n'affiche plus rien
    // pour lui, la page est chargée et tout est terminé. Le client peut même
    // fermer son navigateur, le script peut continuer avec ce que vous voulez. Tout sauf sortie vers le client, bien sûr!
    
    // autre code PHP ... et fin (pas oublier de sortir en beauté car le client ne peut plus appuyer sur STOP si le script tombe en boucle infinie!) 
ripat

Eléphant du PHP | 185 Messages

21 avr. 2009, 10:41

Je sais que c'est vieux, mais... Merci pour l'astuce, elle m'a servi aujourd'hui même ! :)