IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Programmation et administration système Perl Discussion :

Comment savoir si un script perl est terminé ?


Sujet :

Programmation et administration système Perl

  1. #1
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut Comment savoir si un script perl est terminé ?
    Bonjour,

    Je souhaite lancer de manière automatisée plusieurs scripts perl les uns après les autres, sous Windows XP pro.

    La 1ère solution (qui fonctionne bien) est de les lancer à des heures précises en utilisant le gestionnaire de tâches de Windows.

    Le problème est que le 2eme script doit être lancé une fois le 1er script terminé.

    J'ai pensé résoudre le problème en utilisant les id des processus. J'ai testé le module Win32 :: Process :: List, il fournit en effet la liste des processus en exécution. Mais, lorsqu'un script perl est en train de s'exécuter, ce que l'on a comme information sur le processus c'est uniquement "perl.exe" et son id.

    Y a-t-il un moyen d'obtenir précisément le nom du script qui s'exécute ?

    Mais ce n'est peut-être pas la bonne voie.

    Si quelqu'un a déjà résolu ce genre de problème, je serai intéressé par les solutions proposées.

    Merci d'avance.

    Krys006

  2. #2
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Pourquoi ne pas simplement enchaîner les différents programmes dans un script qui ne continue et lance le programme2 que quand le programme1 lui a rendu la main?

  3. #3
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    J'ai pensé en premier à cette possibilité. Mais en procédant ainsi, le script principal est dépendant du script 1. En effet le script 1 télécharge des données à partir d'un serveur.

    Quand tout se passe bien, le temps pour effectuer cette tâche est à peu près constant. Mais quand le temps de fonctionnement du script 1 se prolonge à cause de retard possible dans le téléchargement, voire quand il se bloque, le script principal est bloqué lui aussi.

    Or, je souhaiterai garder un contrôle externe sur les scripts à exécuter.

    Ainsi, si le temps imparti pour le script 1 est dépassé et que celui-ci est toujours lancé, le script principal le ferme et le relance, puis se ferme lui-même. Si le script 1 est terminé, alors le script principal lance le script 2, puis se ferme lui-même.

    Au cas où ce scénario se produirait plusieurs fois, le script principal garde le contrôle sur les autres scripts en s'exécutant toutes les X minutes en tant que tâche programmée.

    C'est la raison pour laquelle je préférerai avoir accès aux scripts en cours de fonctionnement.

    Mais ce n'est peut-être pas la bonne façon de procéder ?

  4. #4
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Hum, il faut probablement utiliser du multi-process (ou du multi-thread).

    De cette façon, le père peut garder le contrôle du fils et savoir quand il se termine.

  5. #5
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    Merci pour ces propositions. Je ne connais pas bien le fonctionnement des scripts perl en mode multi-thread, alors je vais creuser un peu.
    S'il existe un bon tutoriel sur la question, je suis preneur. Cependant, est-il facile de transformer un script classique en script multi-thread s'il n'a
    pas été conçu pour fonctionner ainsi dès le départ ? Car j'ai mis pas mal de temps à écrire les scripts que j'utilise actuellement.

    Je vais quand-même chercher s'il n'existe pas une astuce qui permettrait un fonctionnement acceptable de l'ensemble des scripts tel que je le souhaite, sans que ce soit trop une usine à gaz et même si ça ne respecte pas le contexte "multi-thread" normalement prévu pour ce type de situation.

    Si je trouve quelque chose dans quelques jours, je proposerai une solution.

    En attendant, encore merci pour ta contribution.

    Krys006

  6. #6
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 818
    Points : 499 183
    Points
    499 183
    Par défaut
    Avec Win32::Process, tu peux parfaitement faire ce que tu veux.
    Lit bien la documentation car il te permet d'obtenir pleins d'informations.

    Moi, sans avoir à faire du multithread et company, je ferais ceci.

    ton script 1 se lance. En début de script 1, tu génères un fichier qui contiendra le début (date) d'execution et la pid.

    Ton script 2 se lance et lit ce fichier. S'il est présent => le script 1 tourne et tu compares les dates. si besoin, tu kill le process via l'information contenu dans le fichier. si le fichier n'existe plus. Tu considères qu'il est fini.

    Ou mieux, tu ne fais qu'un seul programme qui lance le programme 1 via Win32::Process. Ainsi, tu auras toutes les informations possible (pid, date de début...).
    Ensuite, tu te fais une boucle qui endort ton programme pendant 1 minute par exemple. Au bout de 60 boucles, si tu estimes que le programme 1 est trop long, tu le kill toujours via Win32::Process et roule ma poule.

    Ce module est excellent et je l'utilise régulièrement lorsque je fais des interface Tk vu que le multithread n'y est pas natif. Il te permet de lancer des programmes externes dans un autre process et tu as donc la main dans ton programme.

    Voilà !

  7. #7
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    Merci pour cette idée. J'étais justement en train d'écrire quelque chose dans le même genre, mais avec 2 fichiers.
    Si je reprends ton raisonnement, il y a juste un point que je ne comprends pas bien. Le script 1 génère un fichier en début d'exécution (disons script_1.log) contenant l'heure.
    Ensuite, le script 2 se lance et regarde si le fichier script_1.log existe, d'accord, mais pour en conclure que cela signifie que le script_1 tourne
    toujours, il faut que ce fichier soit supprimé à la fin du script_1, il me semble ?

    Avant de creuser le module Win32 :: Process qui a l'air d'être l'outil qu'il me faut, voilà ma version qui semble fonctionner avec 2 fichiers, un stockant le début d'exécution et l'autre l'heure d'exécution juste avant de se terminer, mais utilisant cependant les tâches programmées de Windows pour le script qui contrôle les autres.
    C'est peut-être basique, mais pour les personnes qui souhaitent réaliser ce genre d’interaction entre plusieurs scripts, ça permet de trouver une solution
    temporaire à moindre frais, en attendant d'utiliser le multi-process.

    Voilà le fonctionnement en détails :

    TEST en fonctionnement "manuel"

    1- Le script_1 se lance et dès le début crée le fichier DEBUT.txt dans lequel on écrit l'heure (plus la date si nécessaire) et le PID du script_1 grâce à la variable $$.
    Ce script_1 fait ensuite semblant de travailler 60s avec un sleep 60;
    Puis, avant de se terminer, on crée le fichier FIN.txt dans lequel on écrit l'heure de fin et éventuellement le PID.

    2- Lancement du script_gen (qui contrôle les 2 autres)

    A) On lance le script_gen 30 s après, donc avant la fin du script_1
    On teste si le fichier FIN.txt existe, comme ce n'est pas le cas, si on considère qu'il devrait être terminé, on arrête le script_1 grâce à la commande kill et au PID que l'on peut lire dans le fichier DEBUT.txt.

    kill(9,$pid1);

    Puis on relance le script_1 avec la commande system.

    B) On lance le script_gen plus de 60s après.
    Comme le fichier FIN.txt a été crée, c'est suffisant pour conclure que le script_1 a bien été exécuté (même si on peut faire des vérification plus précises). On peut alors lancer le script_2.

    TEST en fonctionnement "auto"

    Si l'on veut que ça fonctionne tout seul, sans le module gérant le multi-process, on utilise les tâches programmées ainsi.

    Supposons que en temps normal, le script_1 fonctionne moins de 5 min, alors :

    1- Tâche programmée : 12h00 - Lancement du script_1

    2- Tâche programmée : 12h05 - Lancement du script_gen

    A) S'il trouve le fichier FIN.txt, le script_1 est terminé et on lance le script_2.
    Le script_gen s'arrête.

    B) S'il ne trouve pas le fichier FIN.txt, le script_1 tourne toujours, on l'arrête et on le relance.

    Mais, pour se trouver à un moment dans la configuration où le fichier FIN.txt existe, il faut que le script_gen soit exécuté à nouveau?
    C'est pourquoi dans la tâche programmée concernant le script_gen, il faut choisir de l'exécuter toutes les 5 min ou plus pour pouvoir laisser au script_1 le temps de s'exécuter correctement une fois relancé. On peut aussi choisir comme option une heure butoir après laquelle le script_gen ne s'exécute plus, mais dans ce cas on n'aura pas la garantie que le script_1 aura bien fait son travail.
    Après, on peut peaufiner. Stocker le nombre de tentatives, et au bout de N essais déclencher une alerte, envoyer un mail, etc.

    C'est sans doute un peu tiré par les cheveux et sûrement moins souple et performant que l'utilisation de Win32 :: Process que je vais m'empresser de mettre en oeuvre rapidement, mais ça peut être une solution temporaire si l'on ne peut s'investir davantage à un moment donné.

    Une dernière question :
    En attendant qu'un script qui ne fait rien se termine, je souhaite afficher un décompte.
    Pourquoi ce qui suit ne marche pas :

    for(my $i=0; $i<=10; $i++) { print "$i "; sleep 1; }

    En règle générale, je rencontre souvent des problèmes lorsque j'insère la commande sleep dans des boucles.

    Ci-dessous le code des scripts.

    Krys006

    Code de script_gen.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    #!usr/bin/perl -w
    use strict;
    use warnings;
     
    my $pid1; # Sert à stocker le PID du script_1
    if(-e "DEBUT.txt") {
      print "Le fichier DEBUT.txt existe\n";
      open(DEBUT,"< DEBUT.txt");
      while(<DEBUT>) {
        if($_ =~ /PID-([0-9]+)/) { print $_; $pid1 = $1; }
        if($_ =~ /DEBUT-[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/) { print $_; }
      }
      close(DEBUT);
    }
    else { print "Le fichier DEBUT.txt n'existe pas\n"; }
     
    if(-e "FIN.txt") {
      print "Le fichier FIN.txt existe\n";
      open(FIN,"< FIN.txt");
      while(<FIN>) {
        if($_ =~ /PID-([0-9]+)/) { print $_; }
        if($_ =~ /FIN-[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/) { print $_; }
      }
      close(FIN);
      print "Lancement de script_2.pl\n";
      system "perl script_2.pl"
    }
    else {
      print "Le fichier FIN.txt n'existe pas\n";
      print "Fermeture de script_1.pl\n";
      kill(9, $pid1);
      print "Lancement de script_1.pl\n";
      system "perl script_1.pl"
    }
    sleep 5;
    Code de script_1.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #!usr/bin/perl -w
    use strict;
    use warnings;
     
    # Création du fichier correspondant au lancement du script
    open(DEBUT,"> DEBUT.txt");
    print "Je suis le script_1\n";
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    if ($hour < 10) { $hour = "0$hour"; }
    if ($min < 10)  { $min  = "0$min";  }
    if ($sec < 10)  { $sec  = "0$sec";  }
    my $heure_debut = $hour.":".$min.":".$sec;
    print DEBUT "PID-$$\n";
    print DEBUT "DEBUT-$heure_debut\n";
    close(DEBUT);
     
     
    # Simulation de travail
    sleep 60;
     
    # Création du fichier correspondant à la fermeture du script
    open(FIN, "> FIN.txt");
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    if ($hour < 10) { $hour = "0$hour"; }
    if ($min < 10)  { $min  = "0$min";  }
    if ($sec < 10)  { $sec  = "0$sec";  }
    my $heure_fin = $hour.":".$min.":".$sec;
    print FIN "PID-$$\n";
    print FIN "FIN-$heure_fin\n";
    close(FIN);
    Code de script_2.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #!usr/bin/perl -w
    use strict;
    use warnings;
     
    print  "Je suis le script_2\n";
     
    # Simulation de travail
    sleep 10;

  8. #8
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Krys006 Voir le message
    En attendant qu'un script qui ne fait rien se termine, je souhaite afficher un décompte.
    Pourquoi ce qui suit ne marche pas :

    for(my $i=0; $i<=10; $i++) { print "$i "; sleep 1; }

    En règle générale, je rencontre souvent des problèmes lorsque j'insère la commande sleep dans des boucles.
    Ce sleep marche, mais les impressions sont bufferisées.

    Essaie ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(my $i=0; $i<=10; $i++) { print "$i \n "; sleep 1; }
    Le retour à la ligne force l'impression.

  9. #9
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    OK, je comprends mieux !
    Merci

  10. #10
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 818
    Points : 499 183
    Points
    499 183
    Par défaut
    Voici une solution avec le module Win32.

    Script main.pl qui lance le script 1 et 2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #!usr/bin/perl
    #===============================================================================
    # Author : djibril
    # Date   : 18/07/2012 13:19:00
    # Main   : Programme gérant les autres programme
    #===============================================================================
    use strict;
    use warnings;
     
    use Win32::Process;
    use Win32::Process::Info;
    use Win32;
    use File::Spec;
     
    my $repertoire_progs         = 'C:\Documents and Settings\user\Bureau';
    my $executable_perl          = 'C:\Perl\bin\perl.exe';
    my $programme_telechargement = 'script-telechargement.pl';
    my $programme2               = 'tache2.pl';
    my $LIMITATION = 25;
     
    # Lancement du programme de téléchargement
    my $ProcessObj;
    print "Debut du telechargement\n";
    Win32::Process::Create($ProcessObj, $executable_perl, $programme_telechargement, 0, NORMAL_PRIORITY_CLASS, $repertoire_progs)|| die ErrorReport();
    my $pid_prog_telechargement = $ProcessObj->GetProcessID();
     
    # Listons les processus tournant sur le PC à intervalle regulier
    my $compteur = 0;
    # Boucle infinie
    INFINI:
    while ( 1 == 1 ) {
      # Si on dépasse le temps imparti, kill
      if ( $compteur > $LIMITATION ) {
        print "Delai depasse - arret programme 1\n";
        $ProcessObj->Kill(0);
        last INFINI;
      }
     
      my $ok = 1;
      my $pi = Win32::Process::Info->new();
      foreach my $ref_info ( $pi->GetProcInfo($pid_prog_telechargement) ) {
        my $pid = $ref_info->{ProcessId};
        if ( $pid == $pid_prog_telechargement ) {
          print "Le programme $programme_telechargement (pid: $pid, Name:$ref_info->{Name}) tourne toujours depuis $compteur secondes\n";
          $ok = 0;
        }
      }
      if ( $ok == 1 ) {
          print "Le programme $programme_telechargement FINI en $compteur secondes\n";
          # Sortons de la boucle
          last INFINI; 
      }
      # Interrogation toutes les 10 secondes
      sleep 10;
      $compteur += 10;
    }
     
    # Lancement du programme 2
    print "Debut de la tache 2 avec la methode system\n";
    system 'perl ' . '"' . File::Spec->catfile($repertoire_progs, $programme2) . '"';
    print "Fin\n";
    script-telechargement.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!usr/bin/perl
    #===============================================================================
    # Author : djibril
    # Date   : 18/07/2012 13:16:04
    # Main   : Programme simulant une longue tâche comme un téléchargement
    #===============================================================================
    use strict;
    use warnings;
     
    # Programme bossant pendant 1 minutes
    print "Programme long\n";
    sleep 30;
    tache2.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!usr/bin/perl
    #===============================================================================
    # Author : djibril
    # Date   : 18/07/2012 13:16:04
    # Main   : Programme simulant une deuxième tâche à accomplir
    #===============================================================================
    use strict;
    use warnings;
     
     
    # Programme bossant pendant 1 minute
    sleep 10;
    Le programme main.pl se charge de lancer les deux programmes et si le temps est dépasser, il arrête le programme 1 et continue.

    Dans le programme main.pl, tu as les variables $repertoire_progs et $LIMITATION à modifier pour le tester.

    Pour le détail des explications tu peux voir ces tutoriels et cours de formation pour apprendre Perl : http://perl.developpez.com/cours/

  11. #11
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    Merci Djibril, c'est super.

    Pendant que tu écrivais cet exemple, de mon côté j'ai creusé un peu le fonctionnement de Win32 :: Process et regarder du coté de la FAQ.
    J'ai écrit quelque chose censé représenter la situation de mes scripts. Du coup, en voyant ton code, le mien me paraît simpliste, mais il semble marcher.
    Je décris comment fonctionne mon exemple et ensuite je pose quelques questions :

    Dans mon script de contrôle (l'équivalent de ton main.pl), je crée le processus 1 qui lance le script 1 (représentant le script de téléchargement) en lui passant en argument le temps d'exécution en sec. Ce script 1 doit obligatoirement être terminé avant de lancer le script 2. Mais s'il met trop de temps, je doit l'arrêter et le relancer.

    Je stocke l'heure de début en secondes (depuis 1970...) dans une variable.
    Puis je boucle toutes les secondes pour savoir si le processus 1 est terminé, en basant mon test sur la valeur de $exitcode (c'est peut-être là qu'est la mauvaise idée ?).

    Si le processus 1 est terminé, c'est bon, je passe au processus 2 qui lance le script 2.

    Si la durée du processus 1 dépasse le délai de fonctionnement, je l'arrête et le relance, mais en passant une autre durée qui se trouve dans le tableau @durees_p1, je réinitialise l'heure de début et j'incrémente le compteur de scénario.
    On attend 1 seconde, et on recommence.

    Quand je teste, ça à l'air de marcher. Maintenant, est-ce que c'est la bonne manière de procéder pour savoir si un process est terminé, alors que toi tu te procures la liste de tous les processus avec le module Win32 :: Process :: Info, puis tu regardes si le pid du processus 1 est dans cette liste.

    Dans les 3 premières exécutions correspondant à 15, 12 et 13 s, il y a interruption du processus 1 et nouvelle exécution. Ce que je trouve bizarre, c'est que lorsqu'on lance manuellement un script et que l'on affiche son pid, à chaque nouveau lancement celui-ci change. Or, dans mon exemple, c'est toujours le même associé à $ProcessObj_1. Je me demande si dans le cas d'un nombre d'appels important dans le cadre d'une boucle comme celle-ci, il n'y a pas une utilisation croissante de la mémoire qui m'échappe et qui pourrait faire planter le script de contrôle au bout d'un certain nombre d'appels.

    C'est cette partie qui me pose problème, et la manière de bien écrire le code.

    Dans ton code, ta boucle sert à s'assurer que le script 1 ne dépasse pas un certain temps d'exécution, auquel cas on le stoppe sans le relancer et on lance le script 2.

    En résumé : Comment s'y prendre correctement pour relancer le même processus dans une boucle ?

    Le script Multi_process_script_cont.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    use Win32::Process;
    use Win32;
     
    sub ErrorReport{
      print Win32::FormatMessage( Win32::GetLastError() );
    }
    my $perl_exe = "C:\\perl\\bin\\perl.exe";
    my $cmd_script_1 = "perl Multi_Process_script_1.pl 15";
    my @durees_p1 = (12,13,7,3); # 4 scénario différents pour le processus 1
    my $temps_max = 10;          # Le processus 1 ne doit pas dépasser ce temps en sec
     
    Win32::Process::Create($ProcessObj_1,$perl_exe,$cmd_script_1,0,NORMAL_PRIORITY_CLASS,".")|| die ErrorReport();
    my $heure_debut = time;   # heure de début de fonctionnement du processus 1
    my $pid_1 = $ProcessObj_1->GetProcessID(); # On récupère le pid pour pouvoir tuer le processus
     
    my $cpt = 0;                 # Compteur pour avancer dans les scénario
    BOUCLE:                      # Boucle qui relance le script 1 tant qu'il ne s'est pas exécuté en moins de $temps_max
    while( 1 == 1 ) {
      my $heure_cour = time;     # heure courante
      my $duree_sec = $heure_cour - $heure_debut;
      print "duree_sec=$duree_sec\n";
      my $exitcode;
      $ProcessObj_1->GetExitCode( $exitcode )."\n"; # Je base mon test de fin du processus sur la valeur de $exitcode
      if( $exitcode !=0 ) {
        if( $duree_sec > $temps_max) { # Le délai du processus 1 est dépassé
          print "Delai depasse - Fin du processus 1\n";
          $ProcessObj_1->Kill( $exitcode );  # On arrête le processus 1
          print "Lancement du processus 1 a nouveau\n";
          $cmd_script_1 = "perl Multi_Process_script_1.pl $durees_p1[$cpt]"; # On relance processus 1 mais avec une autre durée
          Win32::Process::Create($ProcessObj_1,$perl_exe,$cmd_script_1,0,NORMAL_PRIORITY_CLASS,".")|| die ErrorReport();
          $heure_debut = time; # On réactualise l'heure de début du processus 1
          $cpt++; # On passe au scénario suivant
        }
        else {
          print "Le processus 1 pid=$pid_1 tourne depuis $duree_sec secondes\n"; # Le délai du processus 1 n'est pas dépassé
        }
      }
      else {
        print "Le processus 1 ne tourne plus\n"; # Le processus 1 s'est terminé en moins de $temps_max
        last BOUCLE;
      }
      sleep 1;
    }
    # On lance le processus 2 lorsque le processus 1 a fini par faire son exécution en un temps < $temps_max
    my $cmd_script_2 = "perl Multi_Process_script_2.pl";
    Win32::Process::Create($ProcessObj_2, $perl_exe, $cmd_script_2, 0, NORMAL_PRIORITY_CLASS, ".")|| die ErrorReport();
    Le script Multi_process_script_1.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!usr/bin/perl -w
    use strict;
    use warnings;
     
    my $max = $ARGV[0];
    print  "Je suis Multi_Process_script_1.pl $max\n";
     
    # Simulation de travail
    if( defined $max) { for(my $i=1; $i<=$max; $i++) { print "$i\n"; sleep 1; } }
    Le script Multi_process_script_2.pl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #!usr/bin/perl -w
    use strict;
    use warnings;
     
    print  "Je suis Multi_Process_script_2.pl\n";
     
    # Simulation de travail
    for(my $i=1; $i<=10; $i++) { print "  $i\n"; sleep 1; }

  12. #12
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Djibril a juste pas bien interprété l'une de tes contraintes.

    Si tu veux relancer le script 1 si tu as dû le flinguer, tu changes le code qu'il a proposé pour relancer le premier script.

    J'ai cru comprendre que tu voulais dans ce cas lui donner un peu plus de temps avant de le flinguer. Une technique fréquemment employée pour déterminer le nouveau délai de time out dans ce genre de cas est de suivre une suite de Fibonacci (également connu sous le nom de Léanard de Pise):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1, 1, 2, 3, 5, 8, 13, 21, 34, 55, etc.
    dans laquelle chaque terme est la somme des deux termes précédents.

    Cette suite a la propriété que le rapport entre deux termes successifs converge (assez rapidement) vers le nombre d'or (ou la divine proportion): (racine (5) + 1) / 2, soit 1,618033989). Pour prendre un exemple, 55/34 = 1,6176, ce qui est assez proche de la section d'or.

    Je ne vois aucune raison théorique pour laquelle cette suite devrait marcher mieux qu'une autre, mais il semble qu'elle donne souvent de bons résultats pour ce genre de problème. Plusieurs module du CPAN utilisent cette suite pour trouver des intervalles progressifs de time out.

  13. #13
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    Merci pour cette info technique, c'est toujours bon à savoir.

    En fait, si je change le temps d'exécution du script 1, c'est pour simuler des variations dans le temps d'exécution de mon script de téléchargement, et voir si le programme boucle bien jusqu'à ce que le script fonctionne pendant un temps inférieur à temps_max. Mais en ce qui concerne le vrai script, je ne lui passe rien, je sais seulement qu'en temps normal il se termine au bout de 5-6 min.

    Une autre question que j'ai oublié de poser : je ne comprends pas bien le but de l'instruction $ProcessObj->Wait($timeout), en particulier le cas $ProcessObj->Wait(INFINITE).

  14. #14
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    J'ai trouvé mon erreur !

    Dans les 3 premières exécutions correspondant à 15, 12 et 13 s, il y a interruption du processus 1 et nouvelle exécution. Ce que je trouve bizarre, c'est que lorsqu'on lance manuellement un script et que l'on affiche son pid, à chaque nouveau lancement celui-ci change. Or, dans mon exemple, c'est toujours le même associé à $ProcessObj_1.
    Et, oui, erreur de débutant, dans la boucle j'ai oublié de mettre à jour la variable $pid_1 pour qu'elle contienne le pid du nouveau processus créé.

    Donc ça marche ainsi (code du if uniquement) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    if( $duree_sec > $temps_max) { # Le délai du processus 1 est dépassé
          print "Delai depasse - Fin du processus 1 - PID : $pid_1\n";
          $ProcessObj_1->Kill( $exitcode );  # On arrête le processus 1      
          print "Lancement du processus 1 a nouveau\n";
          $cmd_script_1 = "perl Multi_Process_script_1.pl $durees_p1[$cpt]"; # On relance processus 1 mais avec une autre durée
          Win32::Process::Create($ProcessObj_1,$perl_exe,$cmd_script_1,0,NORMAL_PRIORITY_CLASS,".")|| die ErrorReport();
          $heure_debut = time; # On réactualise l'heure de début du processus 1
          $pid_1 = $ProcessObj_1->GetProcessID(); # Mise à jour du pid
          $cpt++; # On passe au scénario suivant
        }
    Une dernière question avant de clore cette discussion.

    Dans la boucle, après avoir tué le processus, ne faut-il pas utiliser une instruction du genre $ProcessObj_1->destroy avant de créer un nouveau processus ?

  15. #15
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 818
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 818
    Points : 499 183
    Points
    499 183
    Par défaut
    Pas besoin, la méthode kill du module tue le processus correctement. Tu peux t'en rendre compte en ouvrant le gestionnaire des taches pendant l'exécution de ton programme.

  16. #16
    Membre du Club
    Profil pro
    Développeur Full Stack
    Inscrit en
    Novembre 2007
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Novembre 2007
    Messages : 101
    Points : 52
    Points
    52
    Par défaut
    Ok, je commence à voir comment tout ça se met en place.

    Merci de m'avoir mis le pied à l'étrier !

    Krys006

Discussions similaires

  1. Réponses: 4
    Dernier message: 15/06/2009, 11h54
  2. Réponses: 9
    Dernier message: 08/12/2004, 15h36
  3. Comment savoir si une impression s'est bien déroulé?
    Par Cyrilh7 dans le forum C++Builder
    Réponses: 5
    Dernier message: 19/11/2003, 21h49
  4. [VB6] comment savoir si la commande shell est terminée ?
    Par ghyscharlotte dans le forum VB 6 et antérieur
    Réponses: 5
    Dernier message: 30/07/2003, 20h12
  5. Réponses: 4
    Dernier message: 10/09/2002, 18h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo