Home > Net >  Django Asyncronous task running syncronously with asgiref
Django Asyncronous task running syncronously with asgiref

Time:11-07

I'm receiving notification in my Django app via API and I should return HTTP 200 before 500 milliseconds. To achieve that I should run the related task asyncronously. I'm using asgiref library for it, everything runs ok but I think is not actualy running asyncronously.

Main viev

In this view I receive the notificacions. I set 2 Print points to check timming in the server log.

@csrf_exempt
@api_view(('POST',))
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def IncommingMeliNotifications(request):
    print('--------------------------- Received ---------------------')
    notificacion = json.loads(request.body)
    call_resource = async_to_sync(CallResource(notificacion))
    print('--------------------------- Answered ---------------------')

    return Response({}, template_name='assessments.html', status=status.HTTP_200_OK)

Secondary view

After receiving the notification I call the secondary view CallResource, which I expect to run asyncronusly.

def CallResource(notificacion):
    do things inside....
    print('--------------------------- Secondary view ---------------------')

    return 'ok'

Log results

When I check the log, I always get the prints in the following order:

print('--------------------------- Received ---------------------')
print('--------------------------- Secondary view ---------------------')
print('--------------------------- Answered ---------------------')

But I suppose that the Secondary viewshould be the last to print, as:

print('--------------------------- Received ---------------------')
print('--------------------------- Answered ---------------------')
print('--------------------------- Secondary view ---------------------')

What am I missing here?

I'm reading the documentation github.com/django/asgiref and as far as I can tell this should be the paradigm I'm working on:

If the outermost layer of your program is synchronous, then all async code run through AsyncToSync will run in a per-call event loop in arbitrary sub-threads, while all thread_sensitive code will run in the main thread.

Any clues welcome. Thanks in advance.

CodePudding user response:

async_to_sync lets a sync thread stop and wait for an async function, not run a sync function asynchronously.

Running an asynchronous task

  1. Since you didn't mention an ASGI server, it appears you are running the sync development server python manage.py runserver.
    If so, install and run Daphne (from Django) instead.
pip install daphne
daphne myproject.asgi:application

If you're using Django 3.x and above, there should already be an asgi.py file in the same directory as your wsgi.py file. See docs.djangoproject.com/en/3.2/howto/deployment/asgi/.

If you're using Django 2.x and below, upgrade to Django 3.x and above and create the asgi.py file. See How to generate asgi.py for existent project?.

  1. You can create an async task when running an ASGI server.
# call_resource = async_to_sync(CallResource(notificacion))
loop = asyncio.get_event_loop()
task = loop.create_task(CallResource(notificacion))
  1. An async function should be defined with async def.
# def CallResource(notificacion):
async def CallResource(notificacion):
  • Related