`use_mutation` and `use_query` are not async
Closed this issue · 1 comments
Current Situation
Due to Django ORM's poor async support, use_mutation and use_query rely on database_sync_to_async with thread_sensitive=True.
This unfortunately means that only one use_query call can execute at a time. We should write the use_query hook to be natively async and support async function calls.
Proposed Actions
For async mutations and query functions:
- Have the developer handle async safety where needed
For sync mutations and query functions:
- Use
thread_senstive=Trueby default, since sync code has a reasonable expectation of thread blocking. - Create a
QueryOptionsparameter to customize the value ofthread_senstive.
Discussed in #132
Originally posted by numpde March 14, 2023
Consider the following component, which is displayed using {% component ... %} from a template in a browser tab A. On button-click, a lengthy use_mutation is executed.
What I find suspicious is that a copy of the component (or any component, for that matter?) would not load in a parallel tab B until the mutation in A completes.
from typing import Callable
from django.utils.timezone import now
from django_idom.hooks import use_mutation
from idom import html, use_state, component
def work(t0, trg: Callable):
import time
time.sleep(10)
trg(now() - t0)
@component
def Main():
sleeper = use_mutation(work)
elapsed = use_state(None)
return html.div(
html.button(
{
'on_click': (lambda e: sleeper.execute(t0=now(), trg=elapsed.set_value)),
'class_name': "btn btn-primary",
'disabled': sleeper.loading,
},
f"Elapsed: {elapsed.value}" if elapsed.value else "use_mutation"
),
)@numpde Can you try using the async mutations and query support on my branch?
pip install git+https://github.com/Archmonger/django-idom@thread-sensitiveimport asyncio
from typing import Callable
from django.utils.timezone import now
from django_idom.hooks import use_mutation
from idom import html, use_state, component
async def work(t0, trg: Callable):
await asyncio.sleep(10)
trg(now() - t0)
@component
def Main():
sleeper = use_mutation(work)
elapsed = use_state(None)
return html.div(
html.button(
{
'on_click': (lambda e: sleeper.execute(t0=now(), trg=elapsed.set_value)),
'class_name': "btn btn-primary",
'disabled': sleeper.loading,
},
f"Elapsed: {elapsed.value}" if elapsed.value else "use_mutation"
),
)Your old sync mutations should also work if using MutationOptions(thread_sensitive=False).