2016-05-29 68 views
0

我發佈了一個關於如何在Python中捕捉「sudo shutdown -r 2」事件的問題。我被髮送到這個線程:Run code in python script on shutdown signal在Python中捕獲關機事件

我正在與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文件不顯示signal.SIGTERM事件已處理。

我在做什麼錯?或者更好的辦法是,如何捕獲關閉事件(通常由cron作業啓動),並優雅地關閉在屏幕會話中運行的Python程序?

+0

您確定處理程序執行時仍然掛載了介質嗎? –

+0

@RDK請檢查我的答案(它適用於我的系統),但也嘗試在'CloseAll'函數體中非常原子化,並關注關閉期間掛載點的可用性http://stackoverflow.com/用戶/ 20862/ignacio-vazquez-abrams如上所示。 – Dilettant

回答

0

當你不嘗試,以等待這樣的事件,但在一個並行會話發送SIGTERM到該進程(例如,通過對進程ID python腳本運行的$PID調用kill -15 $PID),你應該會看到一個啓發性的錯誤信息; - )

在修復python錯誤(TypeError: cannot concatenate 'str' and 'int' objects)後,還應該關注有關掛載點的註釋。

嘗試類似:

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

注意要點:

  1. 日誌文件對於實際測量結果是從記錄信道分離爲運行警報
  2. 日誌文件手柄在上下文管理塊和在通常動作保障只是保持提醒syslog信道被用於開放
  3. 作爲郵件路由示例,我的系統上的syslog.LOG_USER(OS X)爲我在所有終端上提供了一條消息,而信號處理程序中的syslog.LOG_ERR優先級消息僅以系統日誌爲目標。
  4. 應該在關機時更麻煩(不打開文件等))

最後一點(5)是很重要的情況下,所有進程收到一個SIGTERM關閉期間,即所有想要做的事(速度變慢),也許screen也沒有接受任何緩衝輸入了(或不沖洗),注意stdout是塊緩衝不行緩衝。

輸出通道的去耦也應該可以緩解測量日誌文件掛載點的最終消失。

+0

好的,我按照你的建議對我的程序進行了修改。然而,我不確定我是否理解你對「在並行會話中等待事件」的第一條評論。 – RDK

+0

好的,我對我的程序進行了更改。但是,我不確定我是否理解了你的第一條評論。 「在並行會話中等待一個事件」無論如何,我仍然無法讓這個工作,獨立於日誌文件的位置,我懷疑它確實與「sudo shutdown - 當Python程序在「屏幕」窗口中運行時,在主控制檯窗口中發出「r 2」?如果我得到這個工作,cron作業將每週發起一次「shutdown -r 2」命令 – RDK

+0

阿好了,對不起,這個怎麼回事:爲了測試,你可以使用unix命令'kill'來模擬shitdown中收到的信號,如果沒有這種複雜性,在關閉期間所有的服務都會被暫停,並且可能會隱藏錯誤信息。在發送信號時使用鬆弛模式灰。 HTH – Dilettant