1

How to run POST requests (one after another) that calculate something without waiting for the end of calculations?

I want my FastApi work asynchronously. POST method accept two parameters: base and exponent and starts to calculate. The calculate method has a time.sleep() inside which depends on the exponent. The parameters (and the id, status and result) are collected in the database (SQLAlchemy). Status and Result should be updating during the calculation running (one can check the progress with GET request).

I want to process some POST/GET asynchronously, without waiting until the end of the calculation the request triggers.

Does anyone have an idea or hint how to make it work in Python? Thank you in advance.

@router.post("/tasks")
async def create_task(base: int, exponent: int, task_dal: TaskDAL = Depends(get_task_dal)):
    async with async_session() as session:
        async with session.begin():
            task_dal = TaskDAL(session)
            return await task_dal.create_task(base, exponent)


async def calculate(task: Task):
    current_result = 1
    for i in range(task.exponent):
        await time.sleep(1)
        current_result = task.base * current_result
        task.status = ((i / task.exponent) * 100)
    task.result = current_result

async def create_task(self, base: int, exponent: int):
    new_task = Task(base=base, exponent=exponent)
    asyncio.gather(TaskDAL.calculate(new_task))
    self.db_session.add(new_task)
    self.db_session.flush()

In case - all files are in my GitHub repository: https://github.com/wmaterkowska/asynchronous_task_python

UPDATE:

Hi, I rewrote my code with the tips from the comments. Unfortunately it still does not work as it should. It is asynchronous when I open the app in couple different tabs of browser (or in Postman), but that's it. I still do not know how to write it to work fully asynchronously and how to refresh the status of completion of the task.

I was able to achive this all in java but with phyton I still have a problem.

@router.post("/tasks")
async def create_task(base: int, exponent: int, task_dal: TaskDAL = 
Depends(get_task_dal)):
async with async_session() as session:
    async with session.begin():
        task_dal = TaskDAL(session)
        T = task_dal.create_task(base, exponent)

        asyncio.ensure_future(task_dal.update_task(T))

        loop = asyncio.get_running_loop()
        res = await loop.run_in_executor(None, partial(task_dal.calculate, T, session))

        return await asyncio.gather(res)

task_dal:

async def calculate(self, task: Task, db_session: AsyncSession):
    current_result = 1
    for i in range(task.exponent):
        await asyncio.sleep(1)
        current_result = task.base * current_result
        task.status = ((i / task.exponent) * 100)
        await db_session.flush()
    task.result = current_result
    task.status = 100

    return await db_session.flush()

def create_task(self, base: int, exponent: int):
    new_task = Task(base=base, exponent=exponent)

    new_task.status = 0
    new_task.result = 0
    self.db_session.add(new_task)

    return new_task

async def update_task(self, task: Task):
    self.db_session.flush()

I will be gareful for further help and tips.

  • Check how to implement asyncio.gather! – Irfanuddin Sep 09 '22 at 01:10
  • Thank you so much for a tip. Unfortunaltely it still does not work asynhroniously. I added the asyncio.gather to POST request (router.post) create_task method, at the end: return await asyncio.gather(task_dal.create_task(base, exponent)). And I changed from sqlite to postgresql. – Weronika Materkowska Sep 09 '22 at 22:11
  • @WeronikaMaterkowska, are you able to get a basic implementation of asyncio to work ? – D.L Sep 12 '22 at 07:39
  • Yes, if I understood your question correctly. My program works but not asynchronously. That means: I can send the post request but I have to wait until it finishes the calculation to send another one. I am using Postman to test the code. – Weronika Materkowska Sep 12 '22 at 14:06
  • Calling `time.sleep()` will block the event loop. If you need to use the `sleep()` function, then use `asyncio`'s `sleep()` function. Please have a look at [this answer](https://stackoverflow.com/a/71517830/17865804) for more details, as well as [this answer](https://stackoverflow.com/a/74239367/17865804), if for any reason you need to use `asyncio.gather()`. – Chris Nov 10 '22 at 07:04
  • Chris thank you so much for help. I will read carefully everything and let you know if it works. For now - I tried with asyncio sleep() but that alone does not help. – Weronika Materkowska Nov 12 '22 at 23:35

0 Answers0