Re: [Django] #36964: Clarify how persistent connections interact with runserver

6 views
Skip to first unread message

Django

unread,
Mar 13, 2026, 10:13:01 PM (13 days ago) Mar 13
to django-...@googlegroups.com
#36964: Clarify how persistent connections interact with runserver
-------------------------------------+-------------------------------------
Reporter: Adam Sołtysik | Owner: Youssef
Type: | Tarek Ali
Cleanup/optimization | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Youssef Tarek Ali):

* has_patch: 0 => 1

Comment:

Replying to [comment:10 Tim Graham]:
> The quoted statement in the documentation was written by one of Django's
most esteemed contributors (2ee21d9f0d9eaed0494f3b9cd4b5bc9beffffae5).
While something may have changed in the intervening years, we need a more
rigorous explanation.
>
> I believe that multiple threads may be used by the built-in runserver,
even if requests are not concurrent. I verified this making this
modification:
> {{{
> diff --git a/django/db/backends/base/base.py
b/django/db/backends/base/base.py
> index 23015a57a3..94e7197dde 100644
> --- a/django/db/backends/base/base.py
> +++ b/django/db/backends/base/base.py
> @@ -51,6 +51,9 @@ class BaseDatabaseWrapper:
> queries_limit = 9000
>
> def __init__(self, settings_dict, alias=DEFAULT_DB_ALIAS):
> + print("DB Wrapper")
> + import threading
> + print(threading.get_ident())
> # Connection related attributes.
> # The underlying database connection.
> self.connection = None
> }}}
> And making several requests:
> {{{
> Starting WSGI development server at http://127.0.0.1:8000/
> Quit the server with CONTROL-C.
>
> DB Wrapper
> 139299259958976
> [14/Mar/2026 00:41:02] "GET /admin/ HTTP/1.1" 200 11255
> [14/Mar/2026 00:41:04] "GET /admin/polls/choice/ HTTP/1.1" 200 11343
> [14/Mar/2026 00:41:04] "GET /admin/jsi18n/ HTTP/1.1" 200 3342
> [14/Mar/2026 00:41:08] "GET /admin/polls/question/ HTTP/1.1" 200 13477
> DB Wrapper
> 139299250517696
> [14/Mar/2026 00:41:09] "GET /admin/jsi18n/ HTTP/1.1" 200 3342
> [14/Mar/2026 00:41:12] "GET /admin/polls/choice/ HTTP/1.1" 200 1134
> }}}
> I don't believe the AI-generated patch correctly explained the nuances
here.

Thanks for the logs and feedback, Natalia. I see now that my previous
rationale was off.

I wrote this update myself to make sure the technical details are correct.
The new PR explains that database connections are thread-local and that
there's no guarantee of thread reuse for sequential requests, even with
Keep-Alive. I also added a note about the auto-reloader.

The documentation builds correctly locally. Let me know if I've still
missed anything.

New PR: https://github.com/django/django/pull/20905
--
Ticket URL: <https://code.djangoproject.com/ticket/36964#comment:11>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Mar 14, 2026, 5:47:34 AM (13 days ago) Mar 14
to django-...@googlegroups.com
#36964: Clarify how persistent connections interact with runserver
-------------------------------------+-------------------------------------
Reporter: Adam Sołtysik | Owner: Youssef
Type: | Tarek Ali
Cleanup/optimization | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Tim Graham):

How is the development server's behavior different from multithreaded WSGI
servers used in production? Do they "guarantee that sequential requests
will use the same thread"?
--
Ticket URL: <https://code.djangoproject.com/ticket/36964#comment:12>

Django

unread,
Mar 14, 2026, 7:54:21 AM (12 days ago) Mar 14
to django-...@googlegroups.com
#36964: Clarify how persistent connections interact with runserver
-------------------------------------+-------------------------------------
Reporter: Adam Sołtysik | Owner: Youssef
Type: | Tarek Ali
Cleanup/optimization | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Adam Sołtysik):

> The quoted statement in the documentation was written by one of Django's
most esteemed contributors (2ee21d9f0d9eaed0494f3b9cd4b5bc9beffffae5).
While something may have changed in the intervening years, we need a more
rigorous explanation.

The statement was probably correct when it was written, and what changed
later was the keep-alive support added around
https://github.com/django/django/pull/10609.

> How is the development server's behavior different from multithreaded
WSGI servers used in production? Do they "guarantee that sequential
requests will use the same thread"?

It seems that, unlike production servers, runserver generally keeps
creating new threads for each client, as mentioned earlier and confirmed
in a [https://forum.djangoproject.com/t/development-
server/24292/2#:~:text=The%20runserver%20command%20relies%20on%20socketserver.ThreadingMixIn%20which%20defaults%20to%20creating%20one%20thread%20per%20request
forum post]. But the threads are reused with HTTP keep-alive, which allows
persistent DB connections to work.
--
Ticket URL: <https://code.djangoproject.com/ticket/36964#comment:13>

Django

unread,
2:07 AM (16 hours ago) 2:07 AM
to django-...@googlegroups.com
#36964: Clarify how persistent connections interact with runserver
-------------------------------------+-------------------------------------
Reporter: Adam Sołtysik | Owner: Youssef
Type: | Tarek Ali
Cleanup/optimization | Status: assigned
Component: Documentation | Version: 5.2
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by David Smith):

* has_patch: 1 => 0

--
Ticket URL: <https://code.djangoproject.com/ticket/36964#comment:14>
Reply all
Reply to author
Forward
0 new messages