Repository navigation
Conversation
Failing test demonstrating that execute_handler's timeout fires but doesn't free threads blocked in synchronous code (run_in_executor). CancelledError can't be delivered to a blocking sync call, and the finally block waits only 0.1s before abandoning the task.
When a handler is blocked in synchronous code (run_in_executor, C-level call), CancelledError can't be delivered. The finally block waited only 0.1s then abandoned the task silently. Now waits 1s, logs a warning, and releases the global lock so other events can proceed. Fixes the hang; zombie threads are an acknowledged limitation addressed by the companion PR (anyio.to_thread.run_sync).
There was a problem hiding this comment.
All reported issues were addressed across 2 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
When a handler is blocked in synchronous code (via
run_in_executoror a C-level call),CancelledErrorcan't be delivered — it only fires at the nextawaitpoint, which the blocking thread never reaches. Thefinallyblock inexecute_handlerwaited only 0.1s then silently abandoned the task, but the global lock was held during that wait.What this changes
"handler could not be cancelled (still running after 1s). It is likely blocked in synchronous code and will be abandoned as a zombie thread."Limitation
The zombie thread is still alive (Python can't kill threads blocked in C-level code). This PR stops the bus from hanging; the companion PR (#32) addresses the root cause by recommending
anyio.to_thread.run_syncwhich supports proper cancellation.Fixes #31.
Summary by cubic
Abandons uncancellable handler tasks without holding the global lock, preventing bus hangs when a handler blocks in synchronous code. Old behavior: waited 0.1s under the lock and silently abandoned; new behavior: wait up to 1s, emit a warning if still running, then release the lock immediately.
tests/test_handler_timeout_zombie_thread.pyto verify the bus does not hang on a blocking handler.anyio.to_thread.run_syncoverrun_in_executorfor cancellable sync work.Written for commit 21bdec0. Summary will update on new commits.