diff --git a/viahtml/wsgi.py b/viahtml/wsgi.py
index 2fa12644..124fe56e 100644
--- a/viahtml/wsgi.py
+++ b/viahtml/wsgi.py
@@ -1,11 +1,24 @@
"""The application providing a WSGI entry-point."""
+import faulthandler
import os
+import signal
+import sys
# Our job here is to leave this `application` attribute laying around as
# it's what uWSGI expects to find.
from viahtml.app import Application
+
+def _dump_stacks(*args): # pragma: no cover
+ # Print both Python thread and gevent "greenlet" stats and backtraces.
+ #
+ # See https://www.gevent.org/monitoring.html#visibility
+ import gevent
+
+ gevent.util.print_run_info()
+
+
application = Application()
if os.environ.get("SENTRY_DSN"): # pragma: no cover
@@ -17,3 +30,11 @@
# pylint: disable=redefined-variable-type
sentry_sdk.init(dsn=os.environ["SENTRY_DSN"])
application = SentryWsgiMiddleware(application)
+
+# Add a way to dump stacks so we can see what a uWSGI worker is doing if it
+# hangs.
+#
+# We use `SIGCONT` for this because this handler isn't used for anything
+# important, and uWSGI defines its own `SIGUSR1` and `SIGUSR2` handlers after
+# this code runs.
+signal.signal(signal.SIGCONT, _dump_stacks)