Add 2 versions of cornless that are useful for sqlite debugging

This commit is contained in:
Klaas van Schelven
2024-05-23 21:22:44 +02:00
parent 082986f8ad
commit b5fbcfa7c8
2 changed files with 105 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
# 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. This is done by calling the `interrupt()` method on the default connection.
# Because SQLite does not support interrupts, we need to spin up a new thread to run the server, so that the main thread
# can be interrupted with SIGINT. We then call the `interrupt()` method on the default connection to interrupt the
# query.
import sys
import signal
import threading
from wsgiref import simple_server
from bugsink.wsgi import application
from django.db import connections
class ImpureObject(object):
"""'impure' object in the sense that it is not purely 'object()', i.e. it allows setting attributes"""
def handle_sigint(signum, frame):
connections["default"].connection.interrupt()
sys.exit()
def 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()
if __name__ == "__main__":
# we override connections._connections to get rid of the thread-local behavior; this is necessary to be able to
# interrupt the connection from the main thread (I wouldn't know how to do it otherwise)
connections._connections = ImpureObject()
signal.signal(signal.SIGINT, handle_sigint)
t = threading.Thread(target=server)
t.start()
t.join()
+53
View File
@@ -0,0 +1,53 @@
# 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 spins up a new thread to run the server, so that the main thread can be interrupted with SIGINT. This is
# useful when Python's signal-handling is not working, e.g. when running a long-running piece of C code that does not
# regularly do the call to the Python signal check.
# Ideas from:
# https://stackoverflow.com/questions/1032813/dump-stacktraces-of-all-active-threads
# https://stackoverflow.com/a/43242295/339144 (the idea to use a separate thread for the server comes from here, and it
# contains ideas on sqlite3 more generally)
import sys
import signal
import traceback
import threading
# import faulthandler
from wsgiref import simple_server
from bugsink.wsgi import application
def handle_sigint(signum, frame):
print("Caught SIGINT")
# alternatively, a more robust (but uglier) version:
# faulthandler.dump_traceback(all_threads=True)
traceback.print_stack(sys._current_frames()[server_thread.ident])
sys.exit(1)
def 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()
if __name__ == "__main__":
signal.signal(signal.SIGINT, handle_sigint)
server_thread = threading.Thread(target=server)
server_thread.start()
server_thread.join()