-
-
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
base: main
Are you sure you want to change the base?
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 <[email protected]>
❌ 1 Tests Failed:
View the full list of 3 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
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_serv Run pytest with |
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