-
-
Notifications
You must be signed in to change notification settings - Fork 99
Daemonize the serve_unservicable thread #778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In Python < 3.13, the code backfills a shutdown method for a queue, but this isn't complete; an existing get call is not interrupted by shutdown and this means that when the unservicable queue is empty, it never stops, preventing the system from stopping. By daemonizing the unservicable thread, the server can stop and exit. A better solution would probably involve copying a fair amount of code from Python 3.13's queue implementation. In my opinion that isn't worth the maintenance burden. If desired, perhaps we should only daemonize this thread on Python < 3.13. Signed-off-by: David Manthey <david.manthey@kitware.com>
❌ 1 Tests Failed:
View the full list of 3 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
webknjaz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@itamarst since you submitted the original PR, may I ask you to check this bug fix?
@manthey could you add a bugfix change note and maybe a regression test? https://cheroot.cherrypy.dev/en/latest/contributing/guidelines/#adding-change-notes-with-your-prs
|
I will try to look at it on Monday, if I don't do it then, remind me again. |
|
Sorry but Here is a somewhat simple test case to illustrate the problem. It is best to run it without xdist to see it better: diff --git a/cheroot/test/test_server.py b/cheroot/test/test_server.py
index fb5c5468..5c1251d6 100644
--- a/cheroot/test/test_server.py
+++ b/cheroot/test/test_server.py
@@ -611,3 +611,17 @@ def test_overload_results_in_suitable_http_error(request):
response = requests.get(f'http://{localhost}:{port}', timeout=20)
assert response.status_code == HTTPStatus.SERVICE_UNAVAILABLE
+
+
+def test_unservicable_threadleak():
+ before_serv = threading.active_count()
+ # assert before_serv == 1 # <- does not work with xdist ..
+ for _ in range(10):
+ httpserver = HTTPServer(
+ bind_addr=(ANY_INTERFACE_IPV4, EPHEMERAL_PORT),
+ gateway=Gateway,
+ )
+ with httpserver._run_in_thread() as server:
+ import time; time.sleep(0.5)
+
+ assert threading.active_count() == before_servRun pytest with |
|
@itamarst hey, have you had a chance to lurk in? |
|
This seems fine, it's supposed to be a no side-effect add on. |
@itamarst what about the comment above? Looks like the thread remains lingering in some contexts (including maybe cherrypy/cherrypy#2070). @martin-vi you mentioned Python 3.12 — is that the only version you tested? |
|
OK I'll dig in to this Wednesday (tomorrow I'm doing local election volunteering). |
|
@itamarst okay, thanks |
|
UPD: @woodruffw reported that this affects psf/cachecontrol#392 too. |
|
Wednesday I was too sleep deprived to function, but looking at this now. |
|
I went for a different approach in #794. It includes a test based on the reproducer above. |
|
🎉 v11.1.2 just hit PyPI: https://pypi.org/project/cheroot/11.1.2/ This should be fixed via #794 now. |
In Python < 3.13, the code backfills a shutdown method for a queue, but this isn't complete; an existing get call is not interrupted by shutdown and this means that when the unservicable queue is empty, it never stops, preventing the system from stopping. By daemonizing the unservicable thread, the server can stop and exit.
A better solution would probably involve copying a fair amount of code from Python 3.13's queue implementation. In my opinion that isn't worth the maintenance burden. If desired, perhaps we should only daemonize this thread on Python < 3.13.
❓ What kind of change does this PR introduce?
📋 What is the related issue number (starting with
#)Resolves #769
❓ What is the current behavior? (You can also link to an open issue here)
It is impossible to stop a server that has no pending unservicable requests on Python < 3.13.
❓ What is the new behavior (if this is a feature change)?
You can stop a server that has no pending unservicable requests.
This change is