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
Running async_to_sync in a forked process hangs indefinitely (if sync_to_async was called before forking) #194
Comments
Oh yes, this would happen, thinking about how we track parent threads. I can think of a fix for this we can do in the code - storing the current process PID and/or checking for existence of the parent - but writing a test for it is going to be tricky! |
OK, so I've landed a fix for this on master - I don't actually think that the event loop from the parent process persists at all into the child process, so I instead just made it make a new event loop when this situation is detected - it's the safe approach. |
Makes sense, thanks for the quick resolution. |
hi there, I think I'm getting something related to this, I'm doing a django db call inside a Do you have some pointers on how to debug this? I wasn't able to get to a minimal reproduction yet |
@patrick91 Maybe see the discussion on #348. —
What's the This wouldn't explain your observation that it only happens on spawning OSs but... 🤔 |
@carltongibson thanks for getting back to me! The issue in this comment is in another application so there's a possibility that's not related to the one from my mastodon post 😊 I really need to make some time and strip out all the unnecessary things from my app to get to a minimal reproduction and share it here! I'll try to do it again in future :) And thanks for the pointers, I'll use them to share more informations when I try again! <3 |
Minimal Example
Expected
Output of
Observed
Explanation
The third entry to
tasks
forks the process usingmultiprocessing.Process
before callingasync_to_sync
. The synchronous call ofasync_process
in the fork hangs indefinitely.I looked at the asgiref code and I can see the reason... In
AsyncToSync.__init__
the following code obtains an event loop stored atSyncToAsync.threadlocal.main_event_loop
In my minimal example,
sync_to_async
was called before the process was forked, storing the event loop inthreadlocal.main_event_loop
. Once the process is forked, the event loop stored atSyncToAsync.threadlocal.main_event_loop
becomes invalid, however it is still obtained and and used byasync_to_sync
after the fork, resulting in the hanging process. This might really be considered an issue withmultiprocessing.Process
seeming to keep all of thethreadlocal
state, even after forking.(The call to
asyncio.get_event_loop()
threwRuntimeException
I believe because there was no event loop in the forked process thread and the forked process is not the main thread. (https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.get_event_loop)).Workarounds
Placing
force_new_loop=True
inasync_to_sync
works. However I'm not a fan as it spins a new thread and event loop every time, when instead it could create/use the event loop for the forked process instead.Set spawn method of multiprocessing to forkserver using
multiprocessing.set_spawn_method('forkserver')
and create a suitable configuration to fork from that does not have event loops configured yet.Use case
I use django channels which places our synchronous views behind an
AsgiHandler
, which usessync_to_async
on all views. These views may fork long running commands usingmultiprocessing.Process
, these forked commands then may useasync_to_sync
where needed (for instanceasync_to_sync(get_channel_layer().group_send)
). The conditions will result in this indefinite hanging.The text was updated successfully, but these errors were encountered: