#2727·falcon

Add Gunicorn to ASGI server tests and docs

Author: vytas7Created Sep 6, 2026Updated Sep 17, 2026
Labelsdocumentationmaintenance

The recent versions of Gunicorn introduced ASGI support (in addition to WSGI). Add Gunicorn to our ASGI server integration tests (tests/asgi/test_asgi_servers.py), and installation docs (recommend it as an option for ASGI alongside Uvicorn/Granian/etc).

Currently blocking on its WebSocket implementation which seems to be unfinished/non-conformant: https://github.com/benoitc/gunicorn/discussions/3733.

A working patch for the tests (bar some tests failing on the above):

diff
diff --git a/tests/asgi/test_asgi_servers.py b/tests/asgi/test_asgi_servers.py
index ba556f9d..9728cd9d 100644
--- a/tests/asgi/test_asgi_servers.py
+++ b/tests/asgi/test_asgi_servers.py
@@ -555,6 +555,29 @@ def _daphne_factory(host, port):
     )
 
 
+def _gunicorn_factory(host, port):
+    return subprocess.Popen(
+        (
+            sys.executable,
+            '-m',
+            'gunicorn',
+            '--access-logfile',
+            '-',
+            '--bind',
+            f'{host}:{port}',
+            # NOTE(vytas): Not sure if needed (ported verbatim from WSGI tests).
+            '--graceful-timeout',
+            str(_REQUEST_TIMEOUT),
+            '--timeout',
+            str(_REQUEST_TIMEOUT),
+            '--worker-class',
+            'asgi',
+            '_asgi_test_app:application',
+        ),
+        cwd=_MODULE_DIR,
+    )
+
+
 def _hypercorn_factory(host, port):
     if _WIN32:
         script = f"""
@@ -598,6 +621,11 @@ def _can_run(factory):
             import daphne  # noqa
         except Exception:
             pytest.skip('daphne not installed')
+    elif factory == _gunicorn_factory:
+        try:
+            import gunicorn  # noqa
+        except Exception:
+            pytest.skip('gunicorn not installed')
     elif factory == _hypercorn_factory:
         try:
             import hypercorn  # noqa
@@ -610,7 +638,9 @@ def _can_run(factory):
             pytest.skip('uvicorn not installed')
 
 
[email protected](params=[_uvicorn_factory, _daphne_factory, _hypercorn_factory])
[email protected](
+    params=[_daphne_factory, _gunicorn_factory, _hypercorn_factory, _uvicorn_factory]
+)
 def server_base_url(request, requests):
     process_factory = request.param
     _can_run(process_factory)