web-dev-qa-db-fra.com

Expiration d'une fonction dans PHP

Existe-t-il un moyen de temporiser une fonction? J'ai 10 minutes pour effectuer un travail. Le travail inclut une boucle for, voici un exemple:

<?php
foreach($arr as $key => $value){
   some_function($key, $value); //This function does SSH and SFTP stuff
}
?>

$ arr a 15 éléments et some_function () peut parfois prendre plus de 1 minute. En fait, une fois, il a été pendu pendant 5 minutes.

Est-il possible de temporiser l'appel de fonction et de passer à l'élément suivant dans $ arr?

Je vous remercie!!

20
Mo3z

Cela dépend de votre implémentation. 99% des fonctions de PHP sont bloquantes. Cela signifie que le traitement ne continuera pas tant que la fonction en cours ne sera pas terminée. Toutefois, si la fonction contient une boucle, vous pouvez ajouter votre propre code pour l’interrompre après la réalisation de certaines conditions.

Quelque chose comme ça:

foreach ($array as $value) {
  perform_task($value);
}

function perform_task($value) {
  $start_time = time();

  while(true) {
    if ((time() - $start_time) > 300) {
      return false; // timeout, function took longer than 300 seconds
    }
    // Other processing
  }
}

Un autre exemple d'interruption du traitement IS NON possible:

foreach ($array as $value) {
  perform_task($value);
}

function perform_task($value) {
    // preg_replace is a blocking function
    // There's no way to break out of it after a certain amount of time.
    return preg_replace('/pattern/', 'replace', $value);
}
17
Mike B

PHP est mono-threadé ... vous devez utiliser la capacité de votre SE pour lancer un autre processus.

La seule façon pour moi de faire cela est d'utiliser la commande exec pour lancer un autre processus complet. Mettez le contenu de votre choix dans un script séparé, appelez exec sur le script, puis mettez-vous immédiatement en veille pendant 10 min. Si, à 10 minutes, le processus est toujours en cours d'exécution, tuez-le. (vous devriez avoir son PID en faisant en sorte que la commande exécute le nouveau code php en arrière-plan, en le récupérant via une ligne de commande et en le renvoyant à partir de la commande exec).

9
Ray

Ce que vous voulez, c'est utiliser la fonction pcntl_alarm, qui déclenchera un signal SIGALRM à l'expiration du délai d'attente . Par exemple:

// 10 minutes
pcntl_alarm( 600 );
pcntl_signal( 'SIGALRM', function() { print( "I am done!\n" ); exit( 0 ); } );

Veuillez consulter ici le manuel PHP pour plus d'informations: http://php.net/manual/fr/function.pcntl-alarm.php

7
Jacques

Vous pouvez essayer d'implémenter ceci en utilisant 'curl'. Curl est - depuis PHP - principalement utilisé pour les tâches HTTP/FTP, mais il supporte beaucoup plus de protocoles, y compris ssh/sftp. Je n'ai jamais fait quelque chose de ssh/sftp lié en utilisant curl, donc je ne peux donner aucun conseil supplémentaire, mais vous devriez pouvoir trouver des informations supplémentaires ici sur stackoverflow ou ailleurs.

Il existe une option "CURLOPT_TIMEOUT" que vous pouvez utiliser pour configurer le délai d’expiration de votre demande (il existe également une option "CURLOPT_CONNECTTIMEOUT"). Vous pouvez même spécifier les délais d'expiration en millisecondes (CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS). 

Quoi qu'il en soit: pour un travail cronjob, je recommanderais d'utiliser un "fichier de verrouillage" supplémentaire que votre script écrit au démarrage et qu'il supprime, à la fin de son exécution. Vous pouvez rechercher ce fichier de verrouillage dans votre script. Ainsi, si cron déclenche votre script avant la dernière exécution terminée, vous pouvez simplement quitter votre script sans rien faire de plus. Cela garantit que votre script ne sera pas exécuté plusieurs fois en parallèle.

Vous pouvez en savoir plus sur les options CURL et CURL lui-même dans la documentation PHP, également:

Vous devez vous assurer que votre libcurl et/ou curl pour php installés prennent en charge SSH/SFTP, cependant:

etc.

J'espère que cela pourra aider ...

5
aurora

Avant de commencer dans la boucle, définissez une variable qui mémorise la time(). À la fin de chaque itération, vérifiez si la time() actuelle est supérieure de plus de 60 secondes. Si oui, break. Par exemple:

<?php
$startTime=time();
foreach($arr as $key => $value){
    some_function($key, $value); //This function does SSH and SFTP stuff
    if (time()-$startTime>60) break; //change 60 to the max time, in seconds.
}
?>
4
D. Strout

Jetez un coup d’œil à set_time_limit . Maintenant, la fonction elle-même ne veut pas vraiment ce que vous voulez, car elle ne prend en compte que le temps d'exécution, ce qui signifie que 5 secondes dans la vie réelle peuvent ne représenter que 0,2 seconde d'exécution. Mais la raison de regarder le lien est pour les commentaires. Il y a quelques solutions que les utilisateurs ont postées. 

1
Recognizer

Pour ceux d'entre vous qui sont en ligne de commande, voyez comment le sommeil est interrompu:

echo date("H:i:s\n");
pcntl_signal(SIGALRM ,function($signal){
echo "arghhh! i got interrupted \n";
},true);

pcntl_alarm(3);
sleep(20);
pcntl_signal_dispatch();


echo date("H:i:s\n");

pcntl_alarm(3);
sleep(20);

echo date("H:i:s\n");

pcntl_signal_dispatch();
echo "end\n";
0
user1418446