#36863: Under WSGI, multiple calls to asgiref.sync.async_to_sync within the same
request do not share the same event loop.
-------------------------------------+-------------------------------------
Reporter: Mykhailo Havelia | Owner: Vishy
Type: | Algo
Cleanup/optimization | Status: closed
Component: HTTP handling | Version: 6.0
Severity: Normal | Resolution: needsinfo
Keywords: async, wsgi | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mykhailo Havelia):
Replying to [comment:9 Jacob Walls]:
Hey. Thanks for response 😌
**Async upside**
Right now async views under the dev server go through `async_to_sync`,
which runs them in a separate event loop. That breaks loop-bound resources
(DB clients, HTTP clients, etc.) and we see errors like "event loop is
closed". This change keeps async work in a consistent per-request loop, so
async code behaves like it does under ASGI. The win is mainly correctness
and lifecycle safety, not raw speed.
**Cost for WSGI-only users**
You're right that the current approach introduces a reference cycle by
wrapping `response.close`. That means the response object is reclaimed on
a GC pass instead of immediately via refcounting.
{{{
gc.disable()
gc.collect()
response = application(environ, start_response)
ref_response = weakref.ref(response)
response.close()
del response
print("before", ref_response() is None)
gc.collect()
print("after", ref_response() is None)
}}}
Output:
{{{
before False
after True
}}}
**Mitigation**
We can avoid the cycle entirely by moving the cleanup hook into the
response layer (registering extra closers instead of wrapping close). That
keeps refcount-based cleanup and makes the WSGI path effectively neutral.
{{{
class HttpResponseBase:
def close(self):
...
signals.request_finished.send(sender=self._handler_class)
for closer in self._after_resource_closers:
try:
closer()
except Exception:
pass
self._after_resource_closers.clear()
}}}
{{{
response._add_after_resorce_closer(cleanup_stack.close)
}}}
What do you think? 🙂
--
Ticket URL: <https://code.djangoproject.com/ticket/36863#comment:10>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/django-updates/0107019c0f6e31fd-d00904fa-5345-4aa2-85ba-21bf5072a26a-000000%40eu-central-1.amazonses.com.