Skip to content

Commit

Permalink
Preserve CurrentThreadExecutor across create_task
Browse files Browse the repository at this point in the history
Fixes django#214.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Loading branch information
andersk committed Mar 18, 2022
1 parent cde961b commit 009ed98
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 1 deletion.
11 changes: 11 additions & 0 deletions asgiref/sync.py
@@ -1,3 +1,4 @@
import asyncio
import asyncio.coroutines
import contextvars
import functools
Expand Down Expand Up @@ -175,6 +176,16 @@ def __call__(self, *args, **kwargs):
if not (self.main_event_loop and self.main_event_loop.is_running()):
# Make our own event loop - in a new thread - and run inside that.
loop = asyncio.new_event_loop()
create_task = loop.create_task

def new_create_task(*args, **kwargs):
task = create_task(*args, **kwargs)
setattr(
task, self.executors._attr_name, {"current": current_executor}
)
return task

loop.create_task = new_create_task
loop_executor = ThreadPoolExecutor(max_workers=1)
loop_future = loop_executor.submit(
self._run_event_loop, loop, awaitable
Expand Down
8 changes: 7 additions & 1 deletion tests/test_sync.py
Expand Up @@ -397,15 +397,21 @@ def test_thread_sensitive_outside_sync():
@async_to_sync
async def middle():
await inner()
await asyncio.create_task(inner_task())

# Inner sync function
# Inner sync functions
@sync_to_async
def inner():
result["thread"] = threading.current_thread()

@sync_to_async
def inner_task():
result["thread2"] = threading.current_thread()

# Run it
middle()
assert result["thread"] == threading.current_thread()
assert result["thread2"] == threading.current_thread()


@pytest.mark.asyncio
Expand Down

0 comments on commit 009ed98

Please sign in to comment.