如果服务器被CTRL + C杀死或中断或崩溃,则执行操作

问题描述 投票:0回答:2

我有一个不断运行的应用程序(从screen -S myapp python3 app.py开始在Linux中,然后我将其分离)。它可能是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提交)被调用?即:

  • 如果服务器被SIGKILL杀死,SIGTERM

  • 如果服务器代码有错误(例如,如果访问了http://example.com/makeitcrash,则为错误)

  • 如果我在终端中(正在运行的screen内,则执行CTRL + C

我本来要使用atexit并在各处添加try: except:,但我认为它将引入许多代码重复,以便为每条路线插入try: except:

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

python flask error-handling bottle atexit
2个回答
0
投票

“ SIGKILL本质上不能被捕获。”

查看此答案https://stackoverflow.com/a/30732799/7527728

对于可能被困的情况,您可以使用with语句,请参见https://www.python.org/dev/peps/pep-0343/

这里有一个非常简单的示例,说明如何定义enterexit块:https://effbot.org/zone/python-with-statement.htm


0
投票

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

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应用程序,以便在关机时无需进行任何清理。 (例如,对每个请求执行持久写入,而不是在内存中进行缓冲。)减少保持的状态量将有助于简化许多事情,包括如何处理崩溃/关机。

© www.soinside.com 2019 - 2024. All rights reserved.