2016-05-29 31 views
0

Ich habe eine Frage über das Abfangen eines "sudo shutdown -r 2" -Ereignisses in Python gestellt. Ich wurde zu diesem Thread gesendet: Run code in python script on shutdown signal.Ein Shutdown-Ereignis in Python einfangen

Ich betreibe eine Raspberry Pi v2 mit Jessy.

Ich habe über

Signal

und haben versucht zu folgen, die Ideen in dem oben genannten Thread lesen, aber bisher habe ich nicht erfolgreich gewesen. Hier ist mein Code:

import time 
import signal 
import sys 
def CloseAll(Code, Frame): 
    f = open('/mnt/usbdrive/output/TestSignal.txt','a') 
    f.write('Signal Code:' + Code) 
    f.write('Signal Frame:' + Frame) 
    f.write('\r\n') 
    f.close() 
    sys.exit(0) 

signal.signal(signal.SIGTERM,CloseAll) 
print('Program is running') 
try: 
    while True: 
#get readings from sensors every 15 seconds 
    time.sleep(15) 

    f = open('/mnt/usbdrive/output/TestSignal.txt','a') 
    f.write('Hello ') 
    f.write('\r\n') 
    f.close() 

except KeyboardInterrupt: 
    f = open('/mnt/usbdrive/output/TestSignal.txt','a') 
    f.write('Done') 
    f.write('\r\n') 
    f.close() 

Das Programm läuft in einem "Bildschirm" Session/Fenster und reagiert wie erwartet zu einem CNTL-C. Wenn ich jedoch die Bildschirmsitzung verlasse, das Programm laufe und "sudo shutdown -r 2" eingebe, startet der Pi nach 2 Minuten erwartungsgemäß neu, aber die Datei TestSignal.txt zeigt nicht an, dass das Ereignis signal.SIGTERM verarbeitet wurde .

Was mache ich falsch? Oder noch besser: Wie kann ich das Shutdown-Ereignis, das normalerweise von einem Cron-Job ausgelöst wird, abfangen und mein Python-Programm, das in einer Bildschirmsitzung ausgeführt wird, ordnungsgemäß schließen?

+0

Sind Sie sicher, dass das Medium noch eingehängt ist, wenn der Handler ausgeführt wird? –

+0

@RDK Bitte überprüfen Sie meine Antwort (es funktioniert auf meinem System), aber versuchen Sie auch in der 'CloseAll' Funktion Körper ziemlich atomaren und haben ein Auge auf die Verfügbarkeit der Mount-Punkt während des Herunterfahrens als http://stackoverflow.com/ Benutzer/20862/Ignacio-Vazquez-Abrams oben angegeben. – Dilettant

Antwort

0

Wenn Sie nicht versuchen, ein solches Ereignis zu warten, aber in einer parallelen Sitzung senden SIGTERM zu diesem Prozess (zB durch kill -15 $PID auf der Prozess-ID $PID des Python-Skript läuft Aufruf), sollten Sie einen lehrreichen Fehlermeldung angezeigt; -)

Auch der Kommentar über den Mount-Punkt sollte von Interesse sein, nachdem Sie die Python-Fehler (TypeError: cannot concatenate 'str' and 'int' objects) repariert haben.

Probieren Sie etwas wie:

import time 
import signal 
import sys 

LOG_PATH = '/mnt/usbdrive/output/TestSignal.txt' 


def CloseAll(Code, Frame): 
    f = open(LOG_PATH, 'a') 
    f.write('Signal Code:' + str(Code) + ' ') 
    f.write('Signal Frame:' + str(Frame)) 
    f.write('\r\n') 
    f.close() 
    sys.exit(0) 

signal.signal(signal.SIGTERM, CloseAll) 
print('Program is running') 
try: 
    while True: 
     # get readings from sensors every 15 seconds 
     time.sleep(15) 

     f = open(LOG_PATH, 'a') 
     f.write('Hello ') 
     f.write('\r\n') 
     f.close() 

except KeyboardInterrupt: 
    f = open(LOG_PATH, 'a') 
    f.write('Done') 
    f.write('\r\n') 
    f.close() 

als Ausgangspunkt. Wenn dies irgendwie auf Ihrem System funktioniert, warum nicht einige Teile neu zu schreiben wie:

# ... 8< - - - 
def close_all(signum, frame): 
    with open(LOG_PATH, 'a') as f: 
     f.write('Signal Code:%d Signal Frame:%s\r\n' % (signum, frame)) 
    sys.exit(0) 

signal.signal(signal.SIGTERM, close_all) 
# 8< - - - ... 

bearbeiten: Um den Fehler zu isolieren und mehr anpassen wie Modus Produktion, könnte man den Code wie folgt neu schreiben (vorausgesetzt, dass syslog ist auf der Maschine laufen, die es sein sollte, aber ich auf Geräten dieser Art noch nie gearbeitet):

#! /usr/bin/env python 
import datetime as dt 
import time 
import signal 
import sys 
import syslog 

LOG_PATH = 'foobarbaz.log' # '/mnt/usbdrive/output/TestSignal.txt' 


def close_all(signum, frame): 
    """Log to system log. Do not spend too much time after receipt of TERM.""" 
    syslog.syslog(syslog.LOG_CRIT, 'Signal Number:%d {%s}' % (signum, frame)) 
    sys.exit(0) 

# register handler for SIGTERM(15) signal 
signal.signal(signal.SIGTERM, close_all) 


def get_sensor_readings_every(seconds): 
    """Mock for sensor readings every seconds seconds.""" 
    time.sleep(seconds) 
    return dt.datetime.now() 


def main(): 
    """Main loop - maybe check usage patterns for file resources.""" 
    syslog.syslog(syslog.LOG_USER, 'Program %s is running' % (__file__,)) 
    try: 
     with open(LOG_PATH, 'a') as f: 
      while True: 
       f.write('Hello at %s\r\n' % (
        get_sensor_readings_every(15),)) 
    except KeyboardInterrupt: 
     with open(LOG_PATH, 'a') as f: 
      f.write('Done at %s\r\n' % (dt.datetime.now(),)) 

if __name__ == '__main__': 
    sys.exit(main()) 

Punkte zu beachten:

  1. die Protokolldatei für die tatsächlichen Messungen ist getrennt von dem Protokollierungs Kanal für Betriebs Warnungen
  2. die Protokolldatei Griff in Zusammenhang Verwalten Blöcken und in üblichen Betrieb gesichert wird, wird nur offen gehalten
  3. zum Alarmieren des syslog Kanal verwendet wird.
  4. als Beispiel für die Nachrichtenrouting die syslog.LOG_USER auf meinem System (OS X) gibt mir in allen Terminals eine Nachricht, während die syslog.LOG_ERR Priorität Nachricht im Signal-Handler zielt nur auf das Systemprotokoll.
  5. sollte mehr auf den Punkt während des Herunterfahrens stress (nicht das Öffnen einer Datei usw.)
  6. )

Der letzte Punkt (5) für den Fall wichtig ist, alle Prozesse erhalten ein SIGTERM während des Abschaltens, dh alle etwas tun wollen (Dinge nach unten) zu verlangsamen, vielleicht screen auch nimmt keinen gepufferten Eingang mehr (oder nicht bündig), notieren Sie stdout ist Block gepuffert nicht Zeile gepuffert.

Die Entkopplung der Ausgangskanäle sollte auch das Verschwinden des Mountpunkts der Messprotokolldatei erleichtern.

+0

OK, ich habe die Änderungen an meinem Programm vorgenommen, wie Sie vorgeschlagen haben. Ich bin mir jedoch nicht sicher, ob ich Ihre ersten Kommentare über "Warten auf ein Ereignis in einer parallelen Sitzung" verstanden habe. – RDK

+0

OK, ich habe die Änderungen an meinem Programm vorgenommen. Ich bin mir jedoch nicht sicher, ob ich Ihre ersten Kommentare verstehe "Warten auf ein Ereignis in einer parallelen Sitzung." Unabhängig davon, ich kann es immer noch nicht funktionieren, unabhängig vom Speicherort der Protokolldatei. Ich vermute, es hat etwas damit zu tun, dass die "sudo shutdown - r 2 "wird im Hauptkonsolenfenster ausgegeben, während das Python-Programm in einem" Bildschirm "-Fenster läuft? Wenn ich dies zum Laufen bekomme, wird ein Cron-Job etwa einmal pro Woche den Befehl" shutdown -r 2 "auslösen. – RDK

+0

Ah ok Was ist damit zu tun: Zum Testen können Sie das Signal während des Shitdowns mit dem Unix-Befehl 'kill' simulieren, ohne dass beim Herunterfahren alle Dienste angehalten werden und Fehlermeldungen versteckt werden entspannter Modus beim Senden des Signals in Isola tion. HTH – Dilettant