#35583: asgiref.sync.sync_to_async cannot be affected by close_old_connections
-------------------------------+--------------------------------------
Reporter: AlexandrOnuf | Owner: (none)
Type: Uncategorized | Status: new
Component: Uncategorized | Version:
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Description changed by AlexandrOnuf:
Old description:
> Rel. to https://code.djangoproject.com/ticket/34914#comment:3
> partially rel. to this implementation
> https://github.com/django/channels/blob/main/channels/db.py
>
> 1. Let's assume, that we have django command, that creates a "server"
> that listening for a message from queue, or periodically do some job.
> 2. Second point - our service have async function and requires DB calls
> (dummy example in ''_test'' function)
> 3. let's assume. that we have Postgres DB running in docker compose - and
> to reproduce this bug, we should call **docker compose restart db**
>
> Similar to Django itself and, for example, to Django channels
> https://github.com/django/channels/blob/main/channels/db.py we want to be
> able to close closed connection (simplest way to reproduce - DB was
> restarted).
>
> **Expected behavior:** we are assuming, that we do same steps as we can
> see in Django project examples and we should see **success** message in
> logs.
> **Actual**: we will see ''failure: the connection is closed''
>
> **What we can see in code itself:**
> 1. sync_to_async class will use its own isolated ThreadPoolExecutor
> 2. django connections will be created withing this ThreadPoolExecutor and
> will be unavailable for us (this is my assumption)
>
> **Found workaround**
> Calling this code will implicitly have access to hidden DB pool and will
> close closed connections
>
> {{{
> syncio.run(sync_to_async(close_old_connections)())
> }}}
>
> Notes:
> 1. I'm not really sure - is it a feature request or a bug (taking into
> account, how hard to find theoretical reason of it)
> 2. I didn't dive into details of **async_to_sync** function/class
>
> Code snippet for Django command
> {{{
> import asyncio
> import time
>
> from asgiref.sync import sync_to_async
> from django.db import close_old_connections
> from django.core.management.base import BaseCommand
>
> # This can be any model
> from django.contrib.auth.models import User
>
> class Command(BaseCommand):
> def handle(self, *args, **options):
> while True:
> process_message()
> time.sleep(3)
>
> def process_message():
> print("close_old_connections")
> close_old_connections()
>
> print("run test")
> try:
> test()
> print("success")
> except Exception as e:
> print("failure:", str(e))
> print("done test")
>
> def test():
> asyncio.run(_test())
>
> async def _test():
> """
> Synthetic case - most likely, we will use ``sync_to_async`` as
> decorator for part of functions
> and will use it directly for other calls ``sync_to_async``.
> """
> await User.objects.afirst()
> await sync_to_async(
> User.objects.first
> )()
> await sync_to_async(
> User.objects.first,
> thread_sensitive=False,
> )()
> }}}
New description:
Rel. to https://code.djangoproject.com/ticket/34914#comment:3
partially rel. to this implementation
https://github.com/django/channels/blob/main/channels/db.py
1. Let's assume, that we have django command, that creates a "server" that
listening for a message from queue, or periodically do some job.
2. Second point - our service have async function and requires DB calls
(dummy example in ''_test'' function)
3. let's assume. that we have Postgres DB running in docker compose - and
to reproduce this bug, we should call **docker compose restart db**
Similar to Django itself and, for example, to Django channels
https://github.com/django/channels/blob/main/channels/db.py we want to be
able to close closed connection (simplest way to reproduce - DB was
restarted).
**Expected behavior:** we are assuming, that we do same steps as we can
see in Django project examples and we should see **success** message in
logs.
**Actual**: we will see ''failure: the connection is closed''
**What we can see in code itself:**
1. sync_to_async class will use its own isolated ThreadPoolExecutor
2. django connections will be created withing this ThreadPoolExecutor and
will be unavailable for us (this is my assumption)
**Found workaround**
Calling this code will implicitly have access to hidden DB pool and will
close closed connections
{{{
asyncio.run(sync_to_async(close_old_connections)())
}}}
Notes:
1. I'm not really sure - is it a feature request or a bug (taking into
account, how hard to find theoretical reason of it)
2. I didn't dive into details of **async_to_sync** function/class
Code snippet for Django command
{{{
import asyncio
import time
from asgiref.sync import sync_to_async
from django.db import close_old_connections
from django.core.management.base import BaseCommand
# This can be any model
from django.contrib.auth.models import User
class Command(BaseCommand):
def handle(self, *args, **options):
while True:
process_message()
time.sleep(3)
def process_message():
print("close_old_connections")
close_old_connections()
print("run test")
try:
test()
print("success")
except Exception as e:
print("failure:", str(e))
print("done test")
def test():
asyncio.run(_test())
async def _test():
"""
Synthetic case - most likely, we will use ``sync_to_async`` as
decorator for part of functions
and will use it directly for other calls ``sync_to_async``.
"""
await User.objects.afirst()
await sync_to_async(
User.objects.first
)()
await sync_to_async(
User.objects.first,
thread_sensitive=False,
)()
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/35583#comment:1>
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 on the web visit
https://groups.google.com/d/msgid/django-updates/01070190918545b2-2fe798cb-c6ac-4721-8652-aa4c35969047-000000%40eu-central-1.amazonses.com.