Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Make non-blocking serve uvicorn thread a daemon with force_exit - #47371

Open
SebTardif wants to merge 1 commit into
huggingface:mainfrom
SebTardif:fix/serve-daemon-thread-hang
Open

Make non-blocking serve uvicorn thread a daemon with force_exit#47371
SebTardif wants to merge 1 commit into
huggingface:mainfrom
SebTardif:fix/serve-daemon-thread-hang

Conversation

@SebTardif

Copy link
Copy Markdown
Contributor

What does this PR do?

Prevents the Python process from hanging when the non-blocking transformers serve uvicorn thread does not exit within kill_server()'s 2s join timeout.

Problem

start_server() creates a non-daemon background thread for uvicorn (daemon=False). kill_server() sets server.should_exit = True and joins with timeout=2. If uvicorn does not leave serve() within 2 seconds:

  1. join returns while the thread is still alive
  2. Because the thread is non-daemon, interpreter shutdown waits forever for it
  3. Tests and other non-blocking callers hang after teardown

This path is used heavily by the serve test suite (non_blocking=True + kill_server() in tearDownClass).

Fix

  1. Mark the uvicorn thread as daemon=True so a stuck serve cannot block process exit after the join timeout.
  2. Set server.force_exit = True in addition to should_exit so uvicorn abandons a stuck graceful shutdown when possible.

The default CLI path (non_blocking=False) still runs uvicorn on the main thread via server.run() and is unchanged.

Origin: Background thread introduced in #41487 (2025-10-16) with daemon=False.

Test:

Red:  daemon=False and missing force_exit fail new unit tests
Green: pytest tests/cli/test_serve.py::TestServeThreadLifecycle  # 2 passed
  • I confirm that this is not a pure code agent PR.

Before submitting

Who can review?

@LysandreJik @SunMarc (serve)

kill_server joins the background uvicorn thread with a 2s timeout. When
the thread is non-daemon and uvicorn does not exit in time, the Python
process hangs forever on interpreter shutdown. Mark the thread daemon and
set server.force_exit so process exit cannot be blocked by a stuck serve.

Signed-off-by: Sebastien Tardif <[email protected]>
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution 🤗!

CI Security Gate — automatic approval blocked

This PR was not automatically approved for CI because the security gate failed.

Possible reasons:

  • The PR touches 50 or more files — only PRs with fewer than 50 changed files are automatically approved
  • A changed file is outside the allowed directories (src/, tests/, docs/, utils/), has a disallowed extension (only .py, .txt, .md permitted outside tests/ and docs/), or is not .md/.yml inside docs/
  • A new high-severity security issue was detected in the changed Python files (Bandit check)

See the workflow run for the exact violations.

A maintainer can review and manually approve CI if a finding is a false positive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant