Détecter un process dans un service

Le
jean-michel bain-cornu
Bonjour,

J'ai un petit problème avec une application python qui tourne sur un
serveur windows 2k3.
L'appli est un service généré avec py2exe (python 2.4.4). C'est un
process qui est démarré par le gestionnaire de service de Windows, et
dont le but est simplement de lancer une autre tâche (exécutable généré
lui aussi avec py2exe). Cette autre tâche se charge d'un certain nombre
de corvées sur le serveur, puis se termine au bout de quelques secondes
maxi.
Le premier exécutable voit alors que la tâche est terminée, attends 1
seconde, et la relance.
Le but de ça, c'est d'avoir un service robuste qui ne se plantera jamais
pour des raisons fonctionnelles, qui ne sera jamais modifié, et qui
s'assurera impertubablement que la tâche sera lancée à intervalles
périodiques.
Le problème majeur, c'est comment voir si la tâche est terminée, afin de
pouvoir en relancer une autre.
J'ai d'abord commencé avec WMI (voir code ci-après), mais ça ne
fonctionne pas dans un service. Pas de symptômes visibles : ça ne marche
pas.
Je m'en suis tiré avec un fichier qui contient le PID et qui est détruit
par la tâche quand son job est fini, mais du coup ça n'est plus robuste
du tout, si la tâche se plante, le fichier PID n'est jamais détruit, et
une nouvelle tâche n'est jamais relancée.
Ma question, c'est comment faire marcher ce *!@"* de WMIService quand il
est utilisé dans un service, ou alors trouver un autre moyen de détecter
si un process tourne ou pas.
Et je sais, c'est plus facile sous Linux, mais je n'ai pas de serveur
Linux sur ce site :-(

A+
jm

# -*- coding: cp1252 -*-
def wprocess(lstProc=[]):
import win32com,win32com.client
WMIService=win32com.client.GetObject(r'winmgmts:{impersonationLevel=impersonate}!//.ootcimv2')
listProcess = WMIService.ExecQuery('Select * from Win32_Process')
for item in listProcess:
if item.Name in lstProc:
return True
if wprocess(['notepad.exe']):
print 'ok' # le print est là pour l'exemple
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
jean-michel bain-cornu
Le #627975
Voilà un test complet (le script de génération, puis le service
lui-même) s'il y en a qui sont intéressés.
Le script tel qu'il est ne fonctionne pas, le service s'arrête avec une
erreur :
The instance's SvcRun() method failed
File "win32serviceutil.pyc", line 785, in SvcRun
File "testjmbc.pyc", line 29, in SvcDoRun
File "testjmbc.pyc", line 40, in wprocess
File "win32comclient__init__.pyc", line 73, in GetObject
File "win32comclient__init__.pyc", line 88, in Moniker
pywintypes.com_error: (-2147221020, 'Syntaxe incorrecte', None, None)
Si quelqu'un a une idée, je suis preneur.
Note : la ligne 40, c'est :
WMIService=win32com.client.GetObject(r'winmgmts:{impersonationLevel=impersonate}!//.rootcimv2')

Merci.


gen.cmd :
@z:
@cd u1jmdevpythonntservice
rmdir/s/q build
rmdir/s/q dist
python setup.py py2exe >py2exe.log
@rmdir/s/q build
@notepad py2exe.log

setup.py :
from distutils.core import setup
import py2exe
setup(
name= 'testjmbc',
version= '1',
service=["testjmbc"],
## console= ['pctime.py'],
)
#setup(service=["pctime"])

testjmbc.py :
# -*- coding: iso-8859-1 -*-
import win32serviceutil
import win32service
import win32event
import win32evtlogutil
import time
import win32com,win32com.client
class testjmbc6(win32serviceutil.ServiceFramework):
_svc_name_ = "testjmbc6"
_svc_display_name_ = "testjmbc6"
def SvcDoRun(self):
import servicemanager
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.timeout000
fileName= r'c:testjmbc6.txt'
tstfic= file(fileName,'w')
tstfic.write('okn')
tstfic.close
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
while 1:
rc=win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
if rc == win32event.WAIT_OBJECT_0:
break
else:
tstfic= file(fileName,'a+')
tstfic.write('loopingn')
if self.wprocess(['notepad.exe']):
tstfic.write('found notepadn')
else:
tstfic.write('found nothingn')
tstfic.write('loop okn')
tstfic.close
time.sleep(1)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def wprocess(self,lstProc=[]):

WMIService=win32com.client.GetObject(r'winmgmts:{impersonationLevel=impersonate}!//.rootcimv2')
listProcess = WMIService.ExecQuery('Select * from Win32_Process')
for item in listProcess:
if item.Name in lstProc:
return True
MC
Le #627974
Bonsoir !

Pour le même genre de problème. Sauf que je ne m'intéresse qu'aux
processus(1), et que mes délais sont différents : je teste toutes les 3
minutes.

Au début, j'ai fait, comme toi, un programme en tâche de fond.

Ensuite, j'ai opté pour un simple batch, lancé par une tache planifiée.
Ce choix, pour avoir une solution non-Python (pour contourner certains
blocages Python).

Récemment, je suis revenu à Python (et WMI), après avoir trouvé un
moyen d'obtenir la ligne de commande de tout processus, sous win-2000
(cette fonction est apparue, pour WMI, avec XP). En effet, il peut y
avoir plusieurs processus avec le même nom, la ligne de commande permet
de faire la différence.

Un petit extrait de code :
______________________________________________________________________
wmihandle = win32com.client.GetObject('winmgmts:')
re_obj = re.compile(r'programmeX.pyw', re.IGNORECASE|
re.MULTILINE)
wmihandle = win32com.client.GetObject('winmgmts:')
process_list = wmihandle.ExecQuery('Select * from Win32_Process
where name="pythonw.exe"')
flag=True
for p in process_list:
if re_obj.search(p.CommandLine):
flagúlse
if flag:
os.chdir("repertoire_du_prog_a_lancer")
os.system('start "" programmeX.pyw param1 param2')
______________________________________________________________________




(1) trop de limitation avec les services, je préfère utiliser des
programmes (ou des .pyw) qui tournent en tâche de fond.

--
@-salutations

Michel Claveau
MC
Le #627973
Re !

Précisions :
- le code précédent fonctionne avec win : XP, 2003, ou Vista
seulement.
- cela ne règle pas le problème du script "bloqué" (genre boucle
infinie, étreinte mortelle, etc.)

--
@-salutations

Michel Claveau
Laurent Pointal
Le #627972
jean-michel bain-cornu wrote:
<zip>
Je m'en suis tiré avec un fichier qui contient le PID et qui est détruit
par la tâche quand son job est fini, mais du coup ça n'est plus robuste
du tout, si la tâche se plante, le fichier PID n'est jamais détruit, et
une nouvelle tâche n'est jamais relancée.


Une idée - autre que celle de Michel - tu pourrais faire que le process en
tache de fond, en plus de son pid, écrive dans le fichier une valeur qu'il
incrémente.
Si le fichier reste trop longtemps sans que cette valeur ne soit
incrémentée, c'est que le process en planté qq part. Bref, un bête
watchdog.


A+

Laurent.

Méta-MCI
Le #627971
Bonsoir !

Une suggestion, en complément de la suggestion de Laurent Pointal
International : àla place d'un fichier disque, utiliser mmap. Cela évitera
tous les problèmes de droist de fichiers, de contrôles anti-virus, etc.
(sauf qu'un fichier, en passant par un serveur, ça permet à un poste d'en
contrôler un autre).

Et, comme variable "variable", perso, j'utilise l'heure. Ainsi, on sait
depuis quand cela ne tourne plus...

Et, à propos d'heures, bonne nuit...
jean-michel bain-cornu
Le #626823
Bonjour,
Pour le même genre de problème. Sauf que je ne m'intéresse qu'aux
processus(1), et que mes délais sont différents : je teste toutes les 3
minutes.

Au début, j'ai fait, comme toi, un programme en tâche de fond.

Ensuite, j'ai opté pour un simple batch, lancé par une tache planifiée.
Ce choix, pour avoir une solution non-Python (pour contourner certains
blocages Python).

(1) trop de limitation avec les services, je préfère utiliser des
programmes (ou des .pyw) qui tournent en tâche de fond.



Je ne connaissais pas la possibilité de lancer une tâche planifiée au
démarrage de la machine, qui semble convenir à mon besoin. Le seul
problème que je vois, c'est qu'il faut que je fasse un utilitaire pour
contrôler la tâche (un peu comme le fait la console des services) ; ça
ne devrait pas être bien méchant, et ça peut même être fait en mode web :-).
Et du coup, comme le programme tourne en userland, je devrais avoir
accès à ce qu'il me faut pour contrôler ma tâche applicative.
Je vais tester dès ce matin.

Merci pour l'idée :-)

jm

jean-michel bain-cornu
Le #626822
Je m'en suis tiré avec un fichier qui contient le PID et qui est détruit
par la tâche quand son job est fini, mais du coup ça n'est plus robuste
du tout, si la tâche se plante, le fichier PID n'est jamais détruit, et
une nouvelle tâche n'est jamais relancée.


Une idée - autre que celle de Michel - tu pourrais faire que le process en
tache de fond, en plus de son pid, écrive dans le fichier une valeur qu'il
incrémente.
Si le fichier reste trop longtemps sans que cette valeur ne soit
incrémentée, c'est que le process en planté qq part. Bref, un bête
watchdog.

J'avais eu l'idée, mais ça ne me plaisait pas trop parce qu'on est un

peu dans le flou quand même : le process pourrait être simplement
endormi. On peut régler ça en mettant l'incrémentation de la valeur
dans un thread séparé.
La tâche de fond devrait aussi s'auto-terminer si jamais le lanceur a
démarré un autre process.

C'est une solution, mais pas forcément facile à bien tester.
Merci quand même :-)

jm


jean-michel bain-cornu
Le #626821
Et, comme variable "variable", perso, j'utilise l'heure. Ainsi, on sait
depuis quand cela ne tourne plus...


Les deux sont utiles en fait ; combien de fois ça a bouclé, et comme tu
l'as dit, depuis quand ça ne tourne plus.
On peut mettre aussi l'âge du Capitaine, et le tablier de la Crêmière...

jean-michel bain-cornu
Le #626819
J'avais eu l'idée, mais ça ne me plaisait pas trop parce qu'on est un
peu dans le flou quand même : le process pourrait être simplement
endormi. On peut régler ça en mettant l'incrémentation de la valeur
dans un thread séparé.
Bof, bof, finalement. Si c'est l'OS qui joue les marchands de sable, on

ne peut pas trop avoir confiance...

jean-michel bain-cornu
Le #631169
Bonsoir,
L'appli est un service généré avec py2exe (python 2.4.4). C'est un
process qui est démarré par le gestionnaire de service de Windows, et
dont le but est simplement de lancer une autre tâche (exécutable généré
lui aussi avec py2exe). Cette autre tâche se charge d'un certain nombre
de corvées sur le serveur, puis se termine au bout de quelques secondes
maxi.
Le premier exécutable voit alors que la tâche est terminée, attends 1
seconde, et la relance.
Le but de ça, c'est d'avoir un service robuste qui ne se plantera jamais
pour des raisons fonctionnelles, qui ne sera jamais modifié, et qui
s'assurera impertubablement que la tâche sera lancée à intervalles
périodiques.
Le problème majeur, c'est comment voir si la tâche est terminée, afin de
pouvoir en relancer une autre.
Après plein d'essais, finalement, un bête "os.spawnv(os.P_WAIT,etc..."

convient tout à fait comme solution à mon problème.
Avant ça, j'utilisais P_NOWAIT, et c'est ça qui m'obligeait à me
préoccuper de la fin du process...
Avec P_WAIT, ça se fait tout seul, que le process se termine normalement
ou pas. Kiss, comme qui dirait...

A+
jm

Publicité
Poster une réponse
Anonyme