2012-12-19 11 views
5

Ho un'applicazione python che deve eseguire un'applicazione proprietaria (che si blocca di tanto in tanto) circa 20.000 volte al giorno.Come avviare l'applicazione di arresto (raramente) nel sottoprocesso

Il problema è quando crash dell'applicazione, Windows fa scattare automaticamente WerFault che manterrà programma di impiccagione, quindi python's subprocess.call() aspetteranno per sempre l'input dell'utente (che l'applicazione deve funzionare nei fine settimana, nei giorni festivi, 24/7 ... quindi questo è non accettabile).

Se però sull'utilizzo sleep; poll; kill; terminate ma ciò significherebbe perdere la capacità di utilizzare communicate(), l'applicazione può essere eseguito da pochi millisecondi a 2 ore, timeout in modo taratura fissa sarà inefficace

Ho anche provato turning on automatic debugging (utilizzare uno script che avrebbe fare un crash dump di un'applicazione e terminare l'id), ma in qualche modo questo howto non funziona sul mio server (WerFault appare ancora e attende l'input dell'utente).

Anche altri tutorial come this non hanno avuto alcun effetto.

Domanda: c'è un modo per impedire a WerFault di visualizzare (in attesa di input dell'utente)? questo è più sistema, quindi, la programmazione domanda

domanda alternativa: c'è un grazioso modo in Python come rilevare crash dell'applicazione (se è stato visualizzato WerFault)

+0

È possibile aggiungere l'applicazione in arresto alla lista di esclusione di wer e quindi dipendere dai dump locali per il dump di arresto anomalo. Guarda http://msdn.microsoft.com/en-us/library/windows/desktop/bb513617%28v=vs.85%29.aspx – nanda

+0

hai visto http://stackoverflow.com/questions/5069224/handling -subprocess-crash-in-windows – n611x007

risposta

2

semplice (e brutto) risposta, monitor per WerFault.exe le istanze di volta in volta, in particolare quello associato con l'PID dell'applicazione incriminata. E uccidilo. Trattare con WerFault.exe è complicato ma non si vuole disabilitarlo - vedere il servizio Windows Error Reporting.

  1. Ottenere un elenco di processi per nome corrispondente a WerFault.exe. Io uso il pacchetto psutil. Fai attenzione con psutil perché i processi sono memorizzati nella cache, usa psutil.get_pid_list().
  2. Decodifica la riga di comando utilizzando argparse. Questo potrebbe essere eccessivo ma sfrutta le librerie Python esistenti.
  3. Identificare il processo che contiene l'applicazione in base al suo PID.

Questa è una semplice implementazione.

def kill_proc_kidnapper(self, child_pid, kidnapper_name='WerFault.exe'): 
    """ 
    Look among all instances of 'WerFault.exe' process for an specific one 
    that took control of another faulting process. 
    When 'WerFault.exe' is launched it is specified the PID using -p argument: 

    'C:\\Windows\\SysWOW64\\WerFault.exe -u -p 5012 -s 68' 
          |    | 
          +-> kidnapper +-> child_pid 

    Function uses `argparse` to properly decode process command line and get 
    PID. If PID matches `child_pid` then we have found the correct parent 
    process and can kill it. 
    """ 
    parser = argparse.ArgumentParser() 
    parser.add_argument('-u', action='store_false', help='User name') 
    parser.add_argument('-p', type=int, help='Process ID') 
    parser.add_argument('-s', help='??') 

    kidnapper_p = None 
    child_p = None 

    for proc in psutil.get_pid_list(): 
     if kidnapper_name in proc.name: 
      args, unknown_args = parser.parse_known_args(proc.cmdline) 
      print proc.name, proc.cmdline 

      if args.p == child_pid: 
       # We found the kidnapper, aim. 
       print 'kidnapper found: {0}'.format(proc.pid) 
       kidnapper_p = proc 

    if psutil.pid_exists(child_pid): 
     child_p = psutil.Process(child_pid) 

    if kidnapper_p and child_pid: 
     print 'Killing "{0}" ({1}) that kidnapped "{2}" ({3})'.format(
      kidnapper_p.name, kidnapper_p.pid, child_p.name, child_p.pid) 
     self.taskkill(kidnapper_p.pid) 
     return 1 
    else: 
     if not kidnapper_p: 
      print 'Kidnapper process "{0}" not found'.format(kidnapper_name) 
     if not child_p: 
      print 'Child process "({0})" not found'.format(child_pid) 

    return 0 

Ora, taskkill funzione richiama taskkill commmand con la corretta PID.

def taskkill(self, pid): 
    """ 
    Kill task and entire process tree for this process 
    """ 
    print('Task kill for PID {0}'.format(pid)) 
    cmd = 'taskkill /f /t /pid {0}'.format(pid) 
    subprocess.call(cmd.split()) 
+1

Prima risposta molto carina :) In pratica sto già facendo qualcosa del genere, ma invece di uccidere il processo, informo gli amministratori tramite nagios in modo che possano creare crash dump o altro. – Vyktor

-2

non vedo alcuna ragione per perché il tuo programma deve andare in crash, trovare il pezzo di codice che causa l'errore e inserirlo in una dichiarazione di prova.

http://docs.python.org/3.2/tutorial/errors.html#handling-exceptions

+0

Il problema è con l'applicazione proprietaria che va in crash. Non possiamo farci niente (supporto scadente) :( – Vyktor

+0

Le applicazioni si bloccano.Questo è un dato di fatto: anche se è la tua applicazione e puoi risolvere il crash, spesso ha senso gestire i crash, in questo caso è un'applicazione di terze parti –

Problemi correlati