question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] async functions are not being invoked in parallel

See original GitHub issue

Investigative information

Please provide the following:
  • Timestamp: 10:08 PM August 7, 2020 (UTC)
  • Function App name:
  • Function name(s) (as appropriate):
  • Core Tools version:

Repro steps

Provide the steps required to reproduce the problem:

Run two invocations of the HTTP triggered function provided below in parallel (at the same time.)

Expected behavior

Provide a description of the expected behavior.

When I invoke the above function twice at the same time, I expect both invocations to finish at the same time.

Actual behavior

Provide a description of the actual behavior observed.

The start and end times reported by the function show that the second invocation is being processed after the first one finished (i.e. after the sleep has finished and the first invocation has returned.)

azure-functions
azure-storage-blob==12.1.0

Related information

Provide any related information
  • Links to source
  • Bindings used

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
gohar94commented, Aug 7, 2020

@Hazhzeng One more thing I noticed is that if you call different functions of the same app in parallel, that works fine. So in this case, if you copy the same function and put it as function with a different name and invoke them at the same time, they in fact do get processed in parallel. It’s just that the same function is not being handled in parallel.

1reaction
Hazhzengcommented, Aug 7, 2020

Really appreciate Gohar looking into the Python dispatcher code and raising the issue to me. This is a real issue as I discussed and did some experiments with Gohar.

Even when the function app is marked as async, the dispatcher is not picking up the next HTTP request when awaiting.

For example:

import logging
import asyncio
from datetime import datetime
import azure.functions as func

# Async requests are never executed parallelly
async def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    start_time = f'Started At: {datetime.utcnow().isoformat()}'
    await asyncio.sleep(10)  # LONG SLEEP HERE
    end_time = f'Ended At: {datetime.utcnow().isoformat()}'

    return func.HttpResponse(
        f"{start_time} / {end_time}",
        status_code=200
    )

When invoking this HTTP trigger 3 times, the Http requests are still handled one after another, resulting 30 seconds of total execution time. What we suppose to see instead, is 3 HTTP requests executed in 10 seconds.

I think what Elvis said when he finished the project, is to expose the async interface to our customers in asyncio.get_event_loop() and await asyncio.wait(), rather than handling the async HTTP requests parallelly. (This explains why when Mark Russinovich tested our product, he uses his custom event loop to achieve parallel execution).

import sys
import logging
import asyncio

from datetime import datetime
import azure.functions as func

async def parallelly_log_info():
    await asyncio.sleep(5)
    logging.info('parallelly_log_info at root logger')

async def parallelly_log_warning():
    await asyncio.sleep(5)
    logging.warning('parallelly_log_warning at root logger')

async def parallelly_log_error():
    await asyncio.sleep(5)
    logging.error('parallelly_log_error at root logger')

# Async interface for customer to use await asyncio.wait() for parallel execution inside 1 request
async def main(req: func.HttpRequest) -> func.HttpResponse:
    loop = asyncio.get_event_loop()

    # Create multiple tasks and schedule it into one asyncio.wait blocker
    task_info: asyncio.Task = loop.create_task(parallelly_log_info())
    task_warning: asyncio.Task = loop.create_task(parallelly_log_warning())
    task_error: asyncio.Task = loop.create_task(parallelly_log_error())

    # WaitAll
    await asyncio.wait([task_info, task_warning, task_error])

    return 'Async Parallel Execution Under One Http Call'

I need to investigate more into this to find out the bottleneck where it prevents running multiple async HTTP requests. Meanwhile, to mitigate this issue, the customer can increase FUNCTIONS_WORKER_PROCESS_COUNT for spawning multiple Python processes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Call async/await functions in parallel - Stack Overflow
The jsbin code appears to be executing promises in parallel, but they are not. When you create promise with new operator, the constructor...
Read more >
Call Multiple async/await Functions Parallel or Sequential
To demonstrate call multiple async/await functions parallel, below is the function process which return promise after a specific time which are ...
Read more >
Error handling with async/await and promises, n² ... - CatchJS
Yes, but only if the function was called with the await syntax, and only if resolve() has not been called for the promise...
Read more >
Understanding the Event Loop, Callbacks, Promises, and ...
The key takeaway here is that callback functions are not asynchronous— setTimeout is the asynchronous Web API responsible for handling ...
Read more >
Async.js
Synchronous iteration functions ... If you get an error like RangeError: Maximum call stack size exceeded. or other stack overflow issues when using...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found