Выполните действие, если сервер был убит или прерван с помощью CTRL + C или упал - PullRequest
0 голосов
/ 05 мая 2020

У меня постоянно работает приложение (запущено в Linux с screen -S myapp python3 app.py, а затем я отключаю его). Это может быть приложение Bottle, приложение Flask или любая другая система, включающая вечно выполняющееся событие l oop:

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() (и, следовательно, фиксация БД) вызывается во всех возможных случаях завершения работы сервера? то есть:

  • если сервер убит с помощью SIGKILL, SIGTERM

  • , если код сервера содержит ошибку (например, если посещается http://example.com/makeitcrash)

  • если я делаю CTRL + C в терминале (внутри запущенного screen)

?

Я собирался использовать atexit и добавить try: except: везде, но я думаю, что это приведет к дублированию кода, чтобы вставить try: except: для каждого маршрута.

Каково общее решение этой проблемы?

Ответы [ 2 ]

1 голос
/ 05 мая 2020

Один из подходов - улавливать сигналы и выполнять очистку при их получении.

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 никогда не может

Я бы также посоветовал не подходить к проблеме таким образом. Вместо этого посмотрите, сможете ли вы спроектировать свое веб-приложение так, чтобы ему не требовалась очистка при завершении работы. (Например, выполняйте длительную запись для каждого запроса вместо буферизации в памяти.) Уменьшение количества состояний, которые вы храните, поможет упростить многие вещи, в том числе то, как обрабатывать сбои / завершения работы.

0 голосов
/ 05 мая 2020

«SIGKILL по самой своей природе не может быть захвачен.»

См. Этот ответ { ссылка }

Вы могли бы использовать оператор with для случаев, когда быть в ловушке, см. https://www.python.org/dev/peps/pep-0343/

Здесь очень простой пример определения блоков enter и exit : https://effbot.org/zone/python-with-statement.htm

...