Processus d'arrière-plan PHP
-
06-07-2019 - |
Question
J'essaie de créer un script PHP. J'ai terminé le script, mais le processus pour lequel il a été conçu prend environ 10 minutes. Ce n’est pas un problème, mais je suppose que je dois garder la page chargée tout ce temps, ce qui est agaçant. Puis-je l'avoir pour que je commence le processus, puis que je revienne 10 minutes plus tard et que je voie le fichier journal qu'il a généré?
La solution
Vous pouvez utiliser " ignore_user_abort (true) & ";
Le script continuera donc à fonctionner (gardez un œil sur la durée du script, ajoutez peut-être & " set_time_limit (0) ")
Mais voici un avertissement: 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 mettre fin au processus! (Été là-bas, fait une boucle sans fin, s’appelant lui-même encore et encore, faisant en sorte que le serveur s’arrête en cri, se faisant crier dessus ...)
Autres conseils
On dirait que vous devriez avoir une file d'attente et un script externe pour le traitement de la file d'attente.
Par exemple, votre script PHP doit insérer une entrée dans une table de base de données et y revenir immédiatement. Ensuite, un cron lancé 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.
J'ai eu beaucoup de problèmes avec ce genre de processus sous Windows; Ma situation était un peu différente dans la mesure où je me fichais de la réponse du & Quotient & Quot; - je voulais que le script démarre et autorise d'autres requêtes de page à passer alors qu'il était occupé à travailler .
Pour une raison quelconque; J'ai eu des problèmes avec soit suspendre d'autres demandes ou de délai d'attente après environ 60 secondes (Apache et PHP ont été définies pour expirer après environ 20 minutes); Il s'avère également que firefox expire au bout de 5 minutes (par défaut), de sorte que vous ne pourrez plus savoir ce qui se passe dans le navigateur sans modifier les paramètres de firefox.
J'ai fini par utiliser les méthodes open et process close pour ouvrir un php en mode CLI comme suit:
pclose(popen("start php myscript.php", "r"));
Ceci (avec start) ouvrirait le processus php, puis tuerait le processus de démarrage en laissant php fonctionner aussi longtemps que nécessaire - encore une fois, il faudrait tuer le processus pour le fermer manuellement. Il n'était pas nécessaire que vous définissiez des délais d'attente et vous pouviez laisser la page actuelle qui l'appelait continuer et afficher quelques détails supplémentaires.
Le seul problème avec cela est que si vous devez envoyer des données au script, vous le feriez soit via une autre source, soit via le & "ligne de commande &"; comme paramètres; qui n'est pas si sécurisé.
a bien fonctionné pour ce dont nous avions besoin et garantit que le script démarre toujours et est autorisé à s'exécuter sans interruption.
Cela peut également vous aider: Exécution de shell asynchrone en PHP
Je pense que la commande shell_exec est ce que vous recherchez.
Cependant, il est désactivé en mode sans échec.
L'article du manuel PHP à ce sujet est disponible à l'adresse suivante: http://php.net/shell_exec
Vous trouverez un article à ce sujet ici: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/
Il existe une autre option que vous pouvez utiliser, exécutez le script CLI ... Il s’exécutera en arrière-plan et vous pourrez même l’exécuter sous forme de tâche cron si vous le souhaitez.
exemple
> #!/usr/bin/php -q
<?php
//process logs
?>
Ceci peut être configuré en tant que travail cron et s’exécutera sans limitation dans le temps. Cet exemple s’applique cependant au système d’exploitation basé sur Unix.
FYI J'ai un script php fonctionnant avec une boucle infinie qui effectue un certain traitement et qui fonctionne depuis 3 mois sans interruption.
Vous pouvez utiliser ignore_user_abort()
pour que le script continue de s'exécuter même si vous fermez votre navigateur ou accédez à une autre page.
Pensez à Gearman
Gearman est un cadre d’application générique pour la gestion de travaux plusieurs machines ou processus. Il permet aux applications de compléter tâches en parallèle, pour traiter la charge et appeler des fonctions entre les langues. Le cadre peut être utilisé dans une variété de applications, des sites Web à haute disponibilité au transport de événements de réplication de base de données.
Cette extension fournit des classes pour écrire des clients Gearman et travailleurs. - Manuel php source
Site officiel de Gearman
Outre la réponse de bastiandoeen, vous pouvez combiner ignore_user_abort(true);
avec une demande cUrl .
Faux avortement de requête en établissant un faible CURLOPT_TIMEOUT_MS
et maintien du 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 souhaitez que cURL expire en moins d’une seconde, vous pouvez utiliser CURLOPT_TIMEOUT_MS, bien qu'il y ait un bogue / & "Feature &"; sur & "Unix-like" systèmes " libcurl expirera immédiatement si la valeur est < 1000 ms avec l'erreur & Quot; erreur cURL (28): le délai d'attente a été atteint & Quot ;. le explication de ce comportement est:
[...]
La solution consiste à désactiver les signaux à l'aide de CURLOPT_NOSIGNAL
pros
- Inutile de changer de méthode (Windows compatible & amp; linux)
- Pas besoin d'implémenter la gestion de la connexion via des en-têtes et des tampons (indépendante du navigateur et de la version de PHP)
inconvénients
- Besoin d'une extension de boucle
Ressources
Zuk.
Je suis à peu près sûr que cela fonctionnera:
<?php
pclose(popen('php /path/to/file/server.php &'));
echo "Server started. [OK]";
?>
Le '& amp;' est important. Il indique au shell de ne pas attendre la fin du processus.
Aussi, vous pouvez utiliser ce code dans votre php (comme & "; bastiandoeen &" dit)
.ignore_user_abort(true);
set_time_limit(0);
dans votre commande d'arrêt du serveur:
<?php
$output;
exec('ps aux | grep -ie /path/to/file/server.php | awk \'{print $2}\' | xargs kill -9 ', $output);
echo "Server stopped. [OK]";
?>
Appelez simplement StartBuffer () avant toute sortie et EndBuffer () lorsque vous souhaitez que le client ferme la connexion. Le code après l'appel de EndBuffer () sera exécuté sur le serveur sans connexion client.
private function StartBuffer(){ @ini_set('zlib.output_compression',0); @ini_set('implicit_flush',1); @ob_end_clean(); @set_time_limit(0); @ob_implicit_flush(1); @ob_start(); } private function EndBuffer(){ $size = ob_get_length(); header("Content-Length: $size"); header('Connection: close'); ob_flush();ob_implicit_flush(1); }