Lostsoul
Lostsoul

Reputation: 26057

How to block response on fastapi until script is ran?

I have a fastapi endpoint that calls a python script but has two problems on GCP:

  1. it always give a success code (because it's not blocking)
  2. The instances is always running as cloud rundoesn't know when to turn it off(because it's not blocking).

I think the problem is blocking :-)

Here's a sample of my code:

async def curve_builder(secret: str):
    os.system("python3 scripts/my_script.py")     
    return {"succcess": True, "status": "Batch job completed"}

Is there a way to let the script and then return a success/fail message once it's done? I'm not sure how to block it, it seems to just return a success as soon as the command is executed.

I'm not sure if this is specific to fastapi or general python.

Upvotes: 0

Views: 950

Answers (2)

BeardOverflow
BeardOverflow

Reputation: 1070

Blocking operations could hang up your current worker. When you want to execute blocking code over a coroutine, send its logic to a executor.

  1. Get the event loop
loop = asyncio.get_running_loop()
  1. Any blocking code must go out of your coroutine. So, your current worker will be able to execute other coroutines.
await loop.run_in_executor(None, func)

For your case, the final result will be:

async def curve_builder(secret: str):
  loop = asyncio.get_running_loop()
  result = await loop.run_in_executor(None, lambda: os.system("python3 scripts/my_script.py"))
  return {"status": result}

You can read further information in the docs: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor

Upvotes: 1

JarroVGIT
JarroVGIT

Reputation: 5359

Assign the ‘os.system()’ call to a variable. The exit code of your script is assigned, so it will wait till it finished, despite being a async method you are working from.

The answer was wrong, I've tested an example setup but could not reproduce the issue.

Script1:

import os
import asyncio

async def method1():
    print("Start of method1")
    os.system("python /path/to/other/script/script2.py")
    print("End of method1")

print("start script1")
asyncio.run(method1())
print("end script1")

Script2:

import asyncio

async def method2():
    print("Start method2")
    await asyncio.sleep(3)
    print("End method2")

print("start async script2")
asyncio.run(method2())
print("end async script2")

Output:

start script1
Start of method1
start async script2
Start method2
End method2
End async script2
End of method
end script1

Upvotes: 0

Related Questions