在Python中捕获关闭事件

时间:2016-05-29 17:16:15

标签: python-2.7 raspberry-pi shutdown

我发布了一个关于如何捕获" sudo shutdown -r 2"的问题。 Python中的事件。我被发送到这个帖子:Run code in python script on shutdown signal

我正在和Jessy一起运行Raspberry 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文件未显示该信号.SIGTERM事件已处理完毕。

我做错了什么?或者更好的是,我如何捕获通常由cron作业启动的关闭事件,并优雅地关闭在屏幕会话中运行的Python程序?

1 个答案:

答案 0 :(得分:0)

如果您不尝试等待此类事件,但在并行会话中将kill -15 $PID发送到该进程(例如,通过在python脚本的进程标识$PID上调用TypeError: cannot concatenate 'str' and 'int' objects你应该看到一条有启发性的错误信息; - )

修复python错误(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< - - - ...

作为起点。如果这在您的系统上以某种方式工作,为什么不重写一些部分,如:

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

编辑:为了进一步隔离错误并更多地适应生产模式,人们可能会重写这样的代码(假设syslog在机器上运行,应该这样,但我从未工作过)在那种设备上):

syslog

注意事项:

  1. 实际测量的日志文件与操作警报的日志记录通道分开
  2. 日志文件句柄在上下文管理块中受到保护,并且在通常的操作中保持打开状态
  3. 用于警告syslog.LOG_USER频道。
  4. 作为消息路由的示例,我的系统(OS X)上的syslog.LOG_ERR为我提供了一条消息,而信号处理程序中的SIGTERM优先级消息仅针对系统日志。 / LI>
  5. 应该在关机麻烦期间(不打开文件等)
  6. 最后一点(5.)非常重要,以防所有进程在关闭期间收到screen,即所有进程都想做某事(减慢速度),也许stdout也不接受任何缓冲再输入(或不刷新),注意template<typename T, typename F> struct S; template<template <typename...> class C, typename R, typename... A> struct S<C<A...>, R(A...)> { using Apply = R(C<A...>::*)(A...); // ... }; 是块缓冲而不是行缓冲。

    输出通道的去耦也应该可以减轻测量日志文件的挂载点的最终消失。