2016-05-29 9 views
0

Я разместил вопрос о том, как поймать событие «sudo shutdown -r 2» в Python. Я был отправлен в эту тему: Run code in python script on shutdown signal.Захват события выключения в Python

Я работаю с малиной Pi v2 с Джесси.

Я прочитал о

сигнал

и попытались следовать идеям в приведенном выше нить, но я до сих пор не увенчались успехом. Вот мой код:

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() 

Программа работает в «экрана» сессии/окна и реагирует, как ожидается, к CNTL-C. Однако, когда я выхожу из сеанса экрана, оставляя программу запущенной и вводя «sudo shutdown -r 2», Pi перезагружается, как и ожидалось через 2 минуты, но файл TestSignal.txt не показывает, что событие signal.SIGTERM было обработано ,

Что я делаю неправильно? Или еще лучше, как я могу захватить событие shutdown, обычно инициированное заданием cron, и изящно закрыть мою программу Python на сеансе экрана?

+0

Вы уверены, что носитель все еще установлен, когда выполняется обработчик? –

+0

@RDK, пожалуйста, проверьте мой ответ (он работает на моей системе), но попробуйте также быть атомарным в корпусе функции «CloseAll» и следить за доступностью точки монтирования во время выключения как http://stackoverflow.com/ пользователей/20862/ignacio-vazquez-abrams, указанных выше. – Dilettant

ответ

0

Когда вы не пытаетесь ждать такое событие, но в параллельной сессии отправить SIGTERM этот процесс (например, путем вызова kill -15 $PID на идентификаторе процесса $PID в управлении питоном скрипт), вы должны увидеть сообщение поучительных ошибок; -)

Также комментарий о точке монтирования должен представлять интерес после устранения ошибок python (TypeError: cannot concatenate 'str' and 'int' objects).

Try что-то вроде:

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() 

в качестве отправной точки. Если это работает как-то в вашей системе, почему бы не переписать некоторые части, как:

# ... 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< - - - ... 

Edit: Для того, чтобы еще больше изолировать ошибку и адаптироваться к производству, как режим, можно переписать код, как это (при условии, что системный журнал является работает на машине, которую он должен, но я никогда не работал на устройствах такого рода):

#! /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()) 

Очки отметить:

  1. файл журнала для фактических измерений отдельно от канала регистрации оперативных оповещений
  2. ручка файла журнала защищена в контекстном управлении блоками и в обычной работе только остается открытым
  3. для оповещения syslog канала используются.
  4. как образец для маршрутизации сообщения syslog.LOG_USER в моей системе (OS X) дает мне во всех терминалах сообщение, в то время как сообщение приоритета syslog.LOG_ERR в обработчике сигналов предназначено только для системного журнала.
  5. должен быть более точным во время остановки работы (не открывать файл и т. Д.).)

Последний пункт (5) имеет важное значение в случае, если все процессы получать SIGTERM во время остановки, то есть все хотят что-то сделать (замедляя вещи вниз), может быть screen также не принимает каких-либо буферизованный ввод больше (или не сбрасывается), примечание stdout блокируется буфером, а не буфером.

Развязка выходных каналов также должна облегчить возможное исчезновение точки монтирования файла журнала измерений.

+0

ОК, я внес изменения в свою программу, как вы сказали. Тем не менее, я не уверен, что понимаю ваши самые первые комментарии о «ожидании события в параллельном сеансе». – RDK

+0

ОК, я внес изменения в свою программу. Однако я не уверен, что понимаю ваши самые первые комментарии о «ожидая события в параллельном сеансе». Несмотря на это, я все еще не могу заставить это работать независимо от местоположения файла журнала. Я подозреваю, что он имеет какое-то отношение к тому, что «sudo shutdown - r 2 "выдается в главном окне консоли, в то время как программа Python запускается в окне« экрана »? Если я получу это для работы, задание cron начнет команду« shutdown -r 2 »примерно раз в неделю. – RDK

+0

Ah ok , извините. Что насчет этого: для тестирования вы можете имитировать сигнал, полученный во время shitdown, с помощью команды unix «kill». Без этого осложнения, что во время выключения все службы будут остановлены, а сообщения об ошибках могут быть скрыты. расслабленный режим при отправке сигнала в изоляции Тион. HTH – Dilettant

Смежные вопросы