Skip to content

Commit 20cab38

Browse files
bboeclaude
andcommitted
Exit cleanly on Ctrl-C
Connection threads inherited ThreadingMixIn's default daemon_threads = False. Because RangeHandler forces HTTP/1.1, browsers hold keep-alive connections open, leaving worker threads blocked in recv(). On Ctrl-C the interpreter waited on those non-daemon threads forever, so the process printed "Goodbye" but never exited (issue #1). Mark connection threads as daemons so they cannot block shutdown, and close the listening socket in a finally block. Closes #1 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 5be9108 commit 20cab38

2 files changed

Lines changed: 12 additions & 0 deletions

File tree

ext_http_server.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,10 @@ def __init__(
259259
class MyServer(socketserver.ThreadingMixIn, SecureHTTPServer):
260260
"""A threaded SecureHTTPServer with basic error filtering."""
261261

262+
# Run connection threads as daemons so a lingering HTTP/1.1 keep-alive
263+
# connection cannot block interpreter shutdown on Ctrl-C (see issue #1).
264+
daemon_threads = True
265+
262266
def handle_error(self, request: socket | tuple[bytes, socket], client_address: Any) -> None: # noqa: ANN401
263267
"""Disable tracebacks on connection close errors."""
264268
_, exc_value, _ = sys.exc_info()
@@ -317,6 +321,8 @@ def main() -> int:
317321
server.serve_forever()
318322
except KeyboardInterrupt:
319323
print("\nGoodbye")
324+
finally:
325+
server.server_close()
320326
return 0
321327

322328

tests/test_ext_http_server.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ def test_server_serves_range_request(secure_server):
156156
assert body == b"56789ABCDEFGHIJ"
157157

158158

159+
def test_server_uses_daemon_threads():
160+
# Daemon connection threads keep lingering keep-alive connections from
161+
# blocking interpreter shutdown on Ctrl-C (see issue #1).
162+
assert MyServer.daemon_threads is True
163+
164+
159165
def test_set_rate_limit_computes_block_size():
160166
RateLimitWriter.set_rate_limit(128)
161167
assert RateLimitWriter.block_size == int(1024 * 128 * RateLimitWriter.INTERVAL_LEN)

0 commit comments

Comments
 (0)