webleads-tracker

cron lancé manuellement s'arrête au bout de 5 minutes

Vincent StartUp
Avatar
Bonjour,

Sur un site j'ai un cron qui envoie par ftp des images sur un autre serveur. Vu le poids des fichiers, le nombre et le débit, le scripts peut durer 30 minutes. Quand j'exécute le cron en manuel via les outils de développement, le cron s'arrête au bout de 5 minutes, alors qu'en programmé il va jusqu'au bout. Ce n'est pas exactement vrai qu'il s'arrête au bout de 5 minutes, il continue un peu le script mais les fichiers envoyé après 5 minutes sont vides (0ko). Coté navigateur, quand je lance le cron, au bout de 5 minutes j'arrive sur une page blanche. Après l'envoi je force un envoi de mail et je reçois bien le mail. Est-ce que ça peut-être lié au navigateur ?

L'envoi ftp se fait via la fonction ftp_put. Avant mon script je fais un set_time_limit(2000). J'affiche les erreurs via la fonction error_get_last après chaque envoi mais c'est vide (ce n'est peut-être pas la bonne fonction ?)

Il y a t'il autre chose à faire pour que ça fonctionne ? limitation de temps, de memoire... J'ai regardé dans le phpinfo, mais je ne vois pas ce qui pourrait me bloquer.

Merci pour vos lumières.
Vincent - StartUp Communication

Thomas [LE KLUB]
Avatar
Salut Vincent,

Si tu as le controle sur le serveur distant, est-ce que ce ne serait pas judicieux de zipper le tout et d'envoyer un seul fichier ? Est-ce que c'est sur un même serveur emajine mais sur deux site différents ?

désolé, mais sinon, je vois pas plus le soucis.

Vincent StartUp
Avatar
salut Thomas.

Non ce n'est pas du tout sur un serveur emajine, et vu la vitesse je pense que c'est un serveur derrière une boxe. Les fichiers doivent être envoyés un par un, c'est galère.

@ Médialibs, dès fois que quelqu'un du labo passerait par là, auriez-vous une info sur le fait que mon script s'arrête au bout de 5 minutes ?

Merci Thomas,
Vincent - StartUp Communication

Célia - Medialibs
Avatar
Bonjour Vincent !

C'est effectivement normal que les scripts CRON lancés manuellement s'arrêtent au bout de 5 minutes, il s'agit du max_execution_time qui est configuré à 5 minutes.

http://www.php.net/manual/fr/info.configuration.php#ini.max-execution-time

Néanmoins, nous te déconseillons d'augmenter ce temps car c'est toujours mieux de lancer le CRON en tant que tel, en modifiant sa période d'exécution :)

J'espère t'avoir éclairé !
Bonne journée,
Célia Dehé - Développeur - Medialibs

Vincent StartUp
Avatar
Salut Célia, merci pour ta réponse.

Pour modifier le max-execution-time, on se sert bien du set_time_limit ? Parce-que dans ce cas là ça ne marche pas car avant ma fonction je fais set_time_limit(2000). C'est pas comme ça qu'il faut faire ?
Vincent - StartUp Communication

Célia - Medialibs
Avatar
Vincent,

Alors, à priori oui, c'est bien set_time_limit qui doit être appelé, mais après consultation de la documentation php, voici ce que je lis en premier commentaire :

You can do set_time_limit(0); so that the script will run forever - however this is not recommended and your web server might catch you out with an imposed HTTP timeout (usually around 5 minutes).http://www.php.net/manual/fr/function.set-time-limit.php#84563

Du coup, il semblerait que ce soit le navigateur qui impose un HTTP timeout.

Tu as vraiment une raison pour lancer ce CRON via les outils de développements ? Ne serait-il pas plus judicieux de le lancer en tant que CRON et éventuellement créer un fichier de logs dans lequel tu écrirais des informations sur le traitement des fichiers ?

A bientôt :)
Célia Dehé - Développeur - Medialibs

Vincent StartUp
Avatar
Ok, je comprends le coup du navigateur qui s'arrête d'attendre au bout de 5 minutes. Je dois lancé le cron manuellement quand la tache automatisé n'a pas marché (pb connexion ftp...).

Comment le lancer en tant que cron depuis le manage. A part en le reprogrammant, je ne vois pas comment faire.

A+
Vincent - StartUp Communication

Célia - Medialibs
Avatar
Comment le lancer en tant que cron depuis le manage. A part en le reprogrammant, je ne vois pas comment faire. Vincent StartUp

Effectivement, il n'y a pas de moyen de le lancer en tant que CRON d'une autre manière qu'en redéfinissant sa période.

Bonne journée ;)
Célia Dehé - Développeur - Medialibs

Vincent StartUp
Avatar
Merci Célia, mais c'était pas la réponse que j'attendais :(

Le problème c'est que c'est le client qui doit lancer le cron manuellement (via une page spécifique), donc il ne peut pas changer les heures de programmation. Je pourrais éventuellement via cette page spécifique venir changer les horaires du fichier specif_cron_XXXX.class.php, mais je trouve ça très limite. Ou alors un autre cron qui se lance toutes les 5 minutes et qui vérifie une variable modifié depuis le manage, mais c'est pas top.

Une autre idée ? Ligne de commande php, shell...
Vincent - StartUp Communication

Thomas [LE KLUB]
Avatar
Bonjour Vincent,

j'ai peut-être une idée un peu "sioux" pour ton problème. Tu pourrais découper le transfert en plusieurs lots et lancer chaque lot par un appel ajax. Cela ferais x exécution de scripts (en parallèle ou à la suite) qui ne bloquerait pas par la limite de temps et déclenchables par une interface html.

En espérant que ça t'aide,
Thomas

Vincent StartUp
Avatar
"sioux", je dirais même "barbare" ta solution :)

C'est dommage qu'on ne puisse pas appeler un cron automatiquement autrement que par la programmation.

J'ai l'impression que ces ça qu'il me faut : http://www.php.net/manual/fr/function.set-time-limit.php#53564 mais c'est un peu trop sioux à mon gout :)

Bon weekend,
Vincent - StartUp Communication

Julien
Hello Vincent,

Voici ce que je ferais dans un cas comme celui-là :

1. le déclenchement manuel switche une variable dans la DB, typiquement, un flag qui vaut 0 ou 1

2. parallèlement à ça, tu as un CRON qui s'exécute toutes les 5 minutes.
Il commence par vérifier l'état du flag, si c'est '0', exit.
Si c'est '1', les choses sérieuses commencent :
- on commence par faire une "queue" des fichiers images à transférer, stockée dans une table spécifique de la DB,
- puis, avec une boucle et un SELECT borné en LIMIT, (nombre d'enregistrements à traiter à déterminer, mais dans tous les cas, générant un temps de traitement inférieur à 5 minutes), tu lances le transfert d'un certain nombre de fichier, que tu marques comme transférés dans ta DB,
- une fois la limite de la boucle atteinte, le script s'interrompt.
On stocke dans la DB l'index du fichier suivant à traiter dans la queue et le nombre max d'enregistrements.
- à l'exécution suivante du CRON, on relance une boucle commençant au fichier suivant et ainsi de suite.
- une fois la queue traitée, on reswitche le flag à 0 en attendant la prochaine exécution.

Cela te permet d'être propre au niveau des temps de traitement et en plus de logguer précisément les fichiers traités.

Voilà, dis-moi ce que tu en penses.

A+
J.

Vincent StartUp
Avatar
Salut Julien, merci pour ta réponse.

En fin de compte la limite des 5 minutes ne s'applique que quand on lance le cron manuellement via requette HTTP. Du coup j'appliquerais sans doute ta solution mais à l'étape 2 j'exécuterais mon cron automatiquement, donc je n'aurais pas besoin de faire cette boucle avec la limite de 5 minutes.
Ce qui m'embête avec cette solution c'est de devoir faire tourner un cron toute les 5 minutes alors que c'est pour une tache qui sera lancée manuellement si la tache automatisée n'a pas fonctionné (ce qui arrivera rarement).
Dans cette solution ils se servent de session curl http://www.php.net/manual/fr/function.set-time-limit.php#53564 (mon lien précédant n'était pas bon), mais ça me parait compliqué et je ne suis pas du tout sûr que ça puisse fonctionné :
      
$c=curl_init($url_path);
curl_setopt($c, CURLOPT_TIMEOUT, 2); // drop connection after 2 seconds
curl_exec($c);
curl_close($c);
 

Je ne sais pas quoi mettre en $url_path car les fichiers php du dossier specif ne sont pas directement accessible. A moins de mettre mon script dans le dossier script mais c'est dangereux, non ?

Je crois que pour l'instant je vais dire au client de m'appeler si il veut lancer le script manuellement :(, en espérant que ça ne soit pas trop souvent.

Bon ap !
Vincent - StartUp Communication

Thomas [LE KLUB]
Avatar
Salut Vincent,

pour ton problème d'url tout ça tu peux utiliser le hook
hook_PublicSite avec la méthode onInit(). Cette méthode sera appelé avant une éventuelle redirection 404 ce qui te permet dans la méthode de faire un truc du genre :

if($_SERVER['REQUEST_URI'] == '/monUrlQuiTue') {
    //faire des choses
    exit;
}


Maintenant, ça résoud pas forcément les problème d'authentification tout ça, pour l'instant j'ai pas eu d'illumination pour faire quelque chose de bien là-dessus. faudrait générer un token à usage unique.

Bonne journée,
Thomas

Vincent StartUp
Avatar
Salut Thomas,

Pour le coup de l'url, c'est pour utiliser avec une session curl ? si oui tu penses que ça fonctionnerait ?

Pour l'authentification, au pire je lui passerais des paramètres (moi pas comprendre token :))

A+
Vincent - StartUp Communication

Thomas [LE KLUB]
Avatar
Pour l'url, oui ça fonctionnera avec curl (c'était le but premier ;) ).

Pour l'authentification j'ai eu une petite idée. Dans ton cron, quand tu détecte une erreur tu génère un fichier avec un code dedans genre un truc généré par uniqueid('grainDeSel', true). Tu ne met rien d'autre dedans.

Ensuite quand tu veux lancer ta cron manuellement depuis le backoffice, dans le code qui génère ton lien vers le lancement tu va lire le contenu du fichier et passe le code en variable $_GET après l'url de ton script.

Dans ton cron, tu vérifie si le fichier existe, s'il existe tu vérifie que le code passé en GET correspond à celui dans le fichier, si c'est pas le cas, tu quitte. Si le fichier n'existe pas c'est que t'es en automatique et qu'il y a pas eu d'erreur. Donc si le fichier existe et que le code correspond tu supprime le fichier et continue la tâche cron. En cas d'erreur ça regénèrera un fichier et la boucle est bouclée.

Par contre ici attention si tu découpe ton fichier en plusieurs lots il ne faut supprimer le fichier qu'au traitement du dernier lot sinon ça stoppera après le premier.

Au passage, merci @Julien qui a bien résumé la méthode pour découper ton cron en lots comme je le suggérais avant, mais j'avais la flemme de décrire tout le process :x

En espérant avoir été clair,
Thomas

Vincent StartUp
Avatar
Merci Thomas,

Dès que j'ai 5 minutes, je teste tout ça. Pour la méthode d'authentification j'ai compris le principe.

Merci à vous tous.
Vincent - StartUp Communication