Does cancelling an async Django view roll back ORM work running via sync_to_async?
0 reputation · 20 Jan 2021, 15:27 UTC
Django's ASGI handler cancels an async view's coroutine when the client disconnects, raising asyncio.CancelledError at the next await point. Cleanup in async views is therefore expected to happen in try/finally blocks that also account for CancelledError inheriting from BaseException since Python 3.8.
The unresolved behavior involves the ORM. Database calls made from an async view are synchronous and run through sync_to_async with thread_sensitive=True by default. When the surrounding coroutine is cancelled, it is unclear whether a query or transaction already executing in that thread is interrupted, and whether Django rolls back an open transaction automatically. The concern is that a cancelled view could still leave partial writes committed, with details possibly varying across ASGI servers and Django versions.
Open questions:
- Does cancelling the view propagate into the executor thread running
sync_to_asyncORM work, or does that work continue to completion? - Is an in-progress transaction rolled back automatically on cancellation, or must writes be wrapped in an explicit
atomicblock to guarantee no partial commit? - What cleanup pattern is recommended so teardown code distinguishes
CancelledErrorfrom ordinary exceptions?