首页 > 解决方案 > 如果服务器被 CTRL+C 杀死或中断或崩溃,则执行操作

问题描述

我有一个不断运行的应用程序(在 Linux 中启动,screen -S myapp python3 app.py然后将其分离)。它可以是一个 Bottle 应用程序、Flask 应用程序或任何其他涉及永久运行事件循环的系统:

import anyframework   # can be bottle, flask or anything else
import sqlite3

@route('/')
def index():
    c = db.cursor()
    c.execute('INSERT INTO test VALUES (?)', ('test',))
    c.close()  # we can't commit here for *each* client request, it would eat 100ms for each request
    return 'hello'

@route('/makeitcrash')
def index():
    sdlfksdfs  # this will generate an error

def cleanup():
    db.commit()

db = sqlite3.connect('test.db')
run()

如何确保cleanup()在服务器终止的所有可能情况下可靠地调用(以及因此 DB 提交)?IE:

?

我正要在任何地方使用atexit和添加try: except:,但我认为它会引入许多代码重复以插入try: except:每条路线。

这个问题的一般解决方案是什么?

标签: pythonflaskerror-handlingbottleatexit

解决方案


一种方法是捕获信号并在收到信号时进行清理。

import signal
import sys

from bottle import run

def handle_signal(signum, frame):
    print(f'handling signal {signum}')
    # do cleanup
    sys.exit(0)

signal.signal(signal.SIGINT, handle_signal)
# also SIGTERM, et al.

run()

注意事项

正如@MarkAllen 指出的那样,SIGKILL永远不会被抓住。

我也建议不要首先以这种方式解决问题。相反,看看您是否可以设计您的 Web 应用程序,使其在关闭时不需要进行任何清理。(例如,对每个请求执行持久写入,而不是在内存中缓冲。)减少您保留的状态量将有助于简化许多事情,包括如何处理崩溃/关闭。


推荐阅读