Skip to content

Conversation

kigawas
Copy link

@kigawas kigawas commented Sep 9, 2025

Fixes #525

After some debugging, I found that main_event_loop is sometimes closed. If it's closed, we should not call_soon_threadsafe

Fixes django#525 

After some debugging, I found that `main_event_loop` is sometimes closed. If it's closed, we should not `call_soon_threadsafe`
@andersk
Copy link
Contributor

andersk commented Sep 9, 2025

If the user called EventLoop.stop, we should respect their choice. We shouldn’t overreact by silently creating a new event loop in a new thread—that’s going to create confusing bugs with async objects associated with the wrong loop, thread unsafety, and programs failing to stop.

@kigawas
Copy link
Author

kigawas commented Sep 10, 2025

It's already "failing to stop" now due to a potential deadlock, do you have another solution?

@andersk
Copy link
Contributor

andersk commented Sep 10, 2025

Is there a reason the answer is any more complicated than “don’t call EventLoop.stop if you want it to keep running”?

@kigawas
Copy link
Author

kigawas commented Sep 10, 2025

In my case, EventLoop.stop was not called explicitly, the event loop just stopped somewhere

[TEST1] main event loop <_UnixSelectorEventLoop running=True closed=False debug=False>
in main event loop, running? True
exc_info (None, None, None) awaitable <coroutine object convert_exception_to_response.<locals>.inner at 0x123d415d0>
result <HttpResponse status_code=401, "application/json">
running_in_main_event_loop True
PASSED
[TEST2] main event loop <_UnixSelectorEventLoop running=True closed=False debug=False>
in main event loop, running? True
exc_info (None, None, None) awaitable <coroutine object convert_exception_to_response.<locals>.inner at 0x122c91f30>
result <HttpResponse status_code=200, "application/json; charset=utf-8">
running_in_main_event_loop True
main event loop <_UnixSelectorEventLoop running=False closed=False debug=False>
in main event loop, running? False
[...stuck...]

@andersk
Copy link
Contributor

andersk commented Sep 10, 2025

Event loops don’t arbitrarily stop themselves. You can look at the code here:

https://github.com/python/cpython/blob/v3.13.7/Lib/asyncio/base_events.py

The only way for BaseEventLoop.is_running() to change from True to False is if BaseEventLoop._thread_id is set to None, which only happens in BaseEventLoop._run_forever_cleanup, which is only called by BaseEventLoop.run_forever if BaseEventLoop._stopping became True, which only happens if BaseEventLoop.stop() was called. (Perhaps by another library function like BaseEventLoop.run_until_complete → _run_until_complete_cb → BaseEventLoop.stop, although it would be weird to be calling both run_forever and run_until_complete on the same event loop.)

Without a reproducible test case, there’s not really anything more I can say.

@kigawas
Copy link
Author

kigawas commented Sep 10, 2025

<_UnixSelectorEventLoop running=False closed=False debug=False>

I misinterpreted.
It's actually not closed but neither running.

@kigawas
Copy link
Author

kigawas commented Sep 10, 2025

I see, if loop is not running, loop.create_task will never create a task and it'll just seem getting stuck

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.

HTTP requests in django api test sometimes never end from version 3.9.0
2 participants