Comment attendre un programme démarré dans un autre shell

20

J'ai un programme qui effectue une grande quantité de travail (prend environ 4 à 5 heures) qui est démarré par cron lorsque toutes les données avec lesquelles il fonctionne deviennent disponibles. Parfois, lorsque j'attends sa fin, j'aimerais pouvoir démarrer un autre programme (interactif) à la fin. l'appel d'attente semble prometteur mais n'attendra que les enfants.

hildred
la source
La seule autre méthode que je peux concevoir est de créer un fichier à partir de cronjob, puis d'utiliser inotifywait sur ce processus, lorsque les fichiers sont supprimés, votre 2e processus (exécutant inotifywait) peut démarrer.
slm
Je pense que vous pourriez faire quelque chose dans ce sens en utilisant ipcégalement la communication interprocessus. man ipc.
slm
Bien que vous ne regardiez pas un service pour le redémarrer, Dieu, Monit ou l'un des autres paquets mentionnés dans ce Q&A ferait aussi le travail: unix.stackexchange.com/questions/75785/…
slm
@slm peut inotify être utilisé sur n'importe quel système de fichiers par exemple attendre sur close_write sur / proc / _pid_ / fd / 1?
hildred
Pas tout à fait sûr, mais cela pourrait être une autre façon de procéder 8-). Il y avait un certain Q dont je me souviens où il y avait de nouvelles fonctionnalités du noyau liées à la surveillance des processus similaires à inotifywait (pour les fichiers). Cette nouvelle fonctionnalité était pour les événements sur le processus, je pensais, mais beaucoup de questions et réponses commencent à fonctionner ensemble dans mon esprit 8-). Je pense que le A a été fourni par moi ou Gilles.
slm

Réponses:

13

Je préfère définitivement la solution EDIT # 3 (voir ci-dessous).

si son pas dans la même coquille utiliser un en boucle avec condition sur ps -p retour vrai. Mettez un sommeil dans la boucle pour réduire l'utilisation du processeur.

while ps -p <pid> >/dev/null 2>&1
do
   sleep 10
done 

ou si votre UNIX prend en charge / proc (par exemple, HP-UX ne le fait toujours pas).

while [[ -d /proc/<pid> ]]
do 
    sleep 10
done

Si vous voulez un timeout

timeout=6  # timeout after 1mn  
while ((timeout > 0)) && ps -p <pid> >/dev/null 2>&1
do
   sleep 10
   ((timeout -= 1))
done 

EDIT # 1

Il y a une autre manière: n'utilisez pas cron . Utilisez la commande batch pour empiler vos travaux.

Par exemple, vous pouvez empiler quotidiennement tous vos travaux. Le lot peut être réglé pour permettre un certain parallélisme afin qu'un travail bloqué n'arrête pas la totalité de la pile (cela dépend du système d'exploitation).

EDIT # 2

Créez un fifo dans votre répertoire personnel:

$ mkfifo ~/tata

à la fin de votre travail:

echo "it's done" > ~/tata

au début de l'autre travail (celui qui attend):

cat ~/tata 

Ce n'est pas du polling, c'est du bon vieux IO de blocage.

EDIT # 3

Utilisation de signaux:

Au début du ou des scripts qui attendent:

echo $$ >>~/WeAreStopped
kill -STOP $$

à la fin de votre long travail:

if [[ -f ~/WeAreStopped ]] ; then
    xargs kill -CONT < ~/WeAreStopped
    rm ~/WeAreStopped
fi
Emmanuel
la source
Sondage, beurk! Belle décision: perdre du temps processeur ou mon temps pour régler le sommeil. Il doit y avoir une meilleure réponse.
hildred
:) Le sondage est bon pour vous, le sondage est apatride, le sondage est fiable.
Emmanuel
l'interrogation est lente, le poling fait perdre du temps au processeur.
hildred
Avec un temps d'exécution de 0,01 s, les 1440 ps exécutés pendant les 4 heures auraient consommé 14,4 s. Beaucoup moins qu'un ordonnanceur gérant les dépendances des emplois: D
Emmanuel
Je pense que c'est probablement la meilleure option: stackoverflow.com/questions/1058047/… , même si c'est hacky.
slm
5

Vous pouvez modifier votre tâche cron pour utiliser un indicateur.

Au lieu de

2  2 * * *           /path/my_binary

Vous pouvez utiliser

2  2 * * *           touch /tmp/i_m_running; /path/my_binary; rm /tmp/i_m_running

Et surveillez simplement ce fichier en script ou même manuellement. S'il existe, votre programme est en cours d'exécution; sinon, n'hésitez pas à faire ce que vous voulez.

L'exemple de script:

while [[ -f /tmp/i_m_running ]] ; do
   sleep 10 ;
done
launch_whatever_you_want

Si vous n'aimez pas utiliser sleep, vous pouvez modifier le script et l'exécuter via cron une fois par X minutes.

Dans ce cas, l'exemple de script sera:

[[ -f /tmp/i_m_running ]] && { echo "Too early" ; exit ; }
launch_whatever_you_want

Cette façon est un peu plus facile, car vous n'avez pas besoin de trouver le PID de votre processus cron.

se ruer
la source
4

Il n'y a aucune possibilité pour un processus d'attendre la fin d'un autre processus, sauf pour un parent d'attendre la fin de l'un de ses processus enfants. Si vous le pouvez, lancez le programme via un script:

do_large_amount_of_work
start_interactive_program

Si vous ne pouvez pas le faire, par exemple avant de commencer la grande quantité de travail à partir d'un travail cron mais le programme interactif à partir du contexte de votre session, alors faites ceci

do_large_amount_of_work
notify_completion

Il existe plusieurs façons de mettre en œuvre notify_completion. Certains environnements de bureau fournissent un mécanisme de notification ( Ouvrir une fenêtre sur un écran X distant (pourquoi "Impossible d'ouvrir l'affichage")? Peut être utile). Vous pouvez également en créer un à l'aide des notifications de modification de fichier. Sous Linux, la fonction de notification de changement de fichier est inotify .

do_large_amount_of_work
echo $? >/path/to/finished.stamp

Réagir à la création de /path/to/finished.stamp:

inotifywait -e close_write -q /path/to/finished.stamp
start_interactive_program

Si vous ne pouvez pas changer la façon dont do_large_amount_of_workest invoqué, mais que vous savez quel fichier il modifie en dernier, vous pouvez utiliser le même mécanisme pour réagir lorsque ce fichier est fermé. Vous pouvez également réagir à d'autres événements tels que le changement de nom d'un fichier (voir le inotifywaitmanuel pour une liste de possibilités).

Gilles 'SO- arrête d'être méchant'
la source
0

Demandez au script déclenché par le cronjob d'invoquer un script shell vide dans lequel vous pouvez insérer des tâches de suivi si vous en avez besoin.

C'est très similaire à l'approche de Gilles.

cronjob-task.sh contient:

# do_large_amount_of_work

./post-execute.sh

post-execute.shest généralement vide, sauf si vous voyez que vous devez déclencher une tâche de suivi.

Daniel F
la source