Old description:
> Wouldn't it be possible to add something like:
>
> __aenter__ = sync_to_async(Atomic.__enter__, thread_sensitive=True)
> __aexit__ = sync_to_async(Atomic.__exit__, thread_sensitive=True)
>
> to the Atomic class to support async calls?
New description:
Wouldn't it be possible to add something like:
{{{ #!python
__aenter__ = sync_to_async(Atomic.__enter__, thread_sensitive=True)
__aexit__ = sync_to_async(Atomic.__exit__, thread_sensitive=True)
}}}
to the Atomic class to support async calls?
--
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:7>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: Hugo Osvaldo Barrera (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:8>
Comment (by Heraldo Lucena):
I opened an issue at the channels repo
https://github.com/django/channels/issues/1937 related to this.
The use case is not rare, it's pretty common on an async codebase. As you
know, async code requires new API definitions on new namespaces, sync
(blocking) and async code can't be mixed. Actually Django forces you to
run the full transaction block inside @sync_to_async decorated functions,
the async API becomes useless, you can't reuse any async code.
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:9>
* owner: nobody => rajdesai24
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:10>
Comment (by rajdesai24):
Hey guys, I wanted to get your suggestion on this as I had been working on
this and testing it out
{{{
class AsyncAtomic:
def __init__(self, using=None, savepoint=True, durable=True):
self.using = using
self.savepoint = savepoint
self.durable = durable
async def __aenter__(self):
self.atomic = transaction.Atomic(self.using, self.savepoint,
self.durable)
await sync_to_async(self.atomic.__enter__)()
return self.atomic
async def __aexit__(self, exc_type, exc_value, traceback):
await sync_to_async(self.atomic.__exit__)(exc_type, exc_value,
traceback)
}}}
----
{{{
class AsyncAtomicTestCase(TestCase):
async def test_atomic(self):
async with AsyncAtomic():
# Create a new object within the transaction
await sync_to_async(SimpleModel.objects.create)(
field=4,
created=datetime(2022, 1, 1, 0, 0, 0),
)
# Verify that the object was created within the transaction
count = await sync_to_async(SimpleModel.objects.count)()
self.assertEqual(count, 1)
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:11>
Comment (by rajdesai24):
I made a new class called Async Atomic and used it as a context decorator,
which worked but you still need to use the sync_to_async
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:12>
* cc: rajdesai24 (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:13>
Comment (by Mike Lissner):
I'm quite bad at async things generally, but I thought I'd chime in to say
that I'm surprised async atomic transactions aren't more of a priority. A
few of the comments above seem to imply that this isn't an important
feature or that it's an antipattern (maybe?).
I just turned down part of a PR where a developer is converting our code
to async because to do so required that we drop the @transaction.atomic
decorator. I said, "Sorry, we can't covert this to async because given
the choice between correctness and performance, I have to choose
correctness."
Am I missing something big — Isn't this a big gap in Django's support for
real applications converting fully to async?
Thanks all, sorry I don't have more to add! If I were better at async, I'd
take a crack at actually fixing it.
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:14>
* cc: moritz89 (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:15>
* cc: Tyson Clugg (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:16>
* cc: Julien Enselme (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/33882#comment:17>