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 view
should 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
- 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?.
- 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))
- An async function should be defined with
async def
.
# def CallResource(notificacion):
async def CallResource(notificacion):