From 55d1aa463cb8240a7861b39cc159ddbd83791857 Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Thu, 23 May 2024 22:52:31 +0200 Subject: [PATCH] Yet another version of the cornless business --- cornless-set-progress-handler.py | 66 ++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 cornless-set-progress-handler.py diff --git a/cornless-set-progress-handler.py b/cornless-set-progress-handler.py new file mode 100644 index 0000000..103a2bd --- /dev/null +++ b/cornless-set-progress-handler.py @@ -0,0 +1,66 @@ +# A super-simple utility to run the WSGI application using the built-in WSGI server. The usefulness of this script is +# precisely because there is _no_ special handling of SIGINT. This means that SIGINT can be used to get a traceback +# from the application as it was when interrupted. This is useful to answer the question "why is this application +# stuck?" + +# This version is for SQLite. sqlite3 does not support interrupts (i.e. it does not check with Python's signal handler), +# so we need to do it ourselves. In this case we attempt that by setting a progress handler that checks for a global +# variable that is set by the signal handler. + +# This solution prints a stack trace, but then hangs for reasons I don't understand. +# (a version without a signal handler (implicit KeyboardInterrupt) works just as well / just as poorly) + +import sys +import signal + +from wsgiref import simple_server +from bugsink.wsgi import application +from django.db.backends.sqlite3.base import DatabaseWrapper + + +interrupted = False + + +def handle_sigint(signal, frame): + global interrupted + interrupted = True + + +signal.signal(signal.SIGINT, handle_sigint) + + +def stop_when_interrupted(): + global interrupted + if interrupted: + interrupted = False + return -1 + return 0 + + +def get_new_connection_with_check(self, conn_params): + conn = original_get_new_connection(self, conn_params) + # this is the first thing I tried; it works just fine, but so does any old python code, because any old python code + # has PyErr_CheckSignals in its execution path. + # conn.set_progress_handler(ctypes.pythonapi.PyErr_CheckSignals, 50) + conn.set_progress_handler(stop_when_interrupted, 50) + # conn.set_progress_handler(lambda: None, 50) # the version without the signal handler (assumes signal.siganl is + # not done, and the lambda is a moment for the regular Python signal handler, which raises keyboardInterrupt, to + # run) + return conn + + +original_get_new_connection = DatabaseWrapper.get_new_connection +DatabaseWrapper.get_new_connection = get_new_connection_with_check + + +if __name__ == "__main__": + # the actual server: + if len(sys.argv) < 2: + host = "127.0.0.1" + port = 8000 + else: + host = sys.argv[1].split(":")[0] + port = int(sys.argv[1].split(":")[1]) + + httpd = simple_server.make_server(host, port, application) + httpd.serve_forever()