I have an application setup using FastAPI and Celery for some CPU intensive tasks (basically some synchronous functions defined). One of the REST endpoints is request_data
defined as async
that users can call to request data. It provides an optional parameter force
that if False
would simply return the data from Cassandra. But, if force
is True
, then the REST endpoint has to perform the CPU intensive task in sync and return the results back in the same request.
Here my problem is that, since the function is defined as async
, calling the CPU intensive task would block the event loop and hamper FastAPI from handling other requests.
I tried to look for following:
- Define two functions (one sync and one
async
). If FastAPI would allow me to add a middleware that can route my request to respective function but it doesn't seem possible. - Submit the task to celery in
async
fashion. But it doesn't seem I canawait
on the result and so waiting otherwise would simply block the event loop. - As a last option, I can make the REST endpoint function as sync but wanted to avoid that. Reason is that I am using Cassandra that provides
async
support viaexecute_async
on which I canawait
. Making the REST endpoint function sync would take awayasync
benefits on Cassandra IO.
Does any one has any suggestions on this? I understand that calling a synchronous function in an asynchronous function would eventually mean that event loop would have to perform the CPU intensive task. My only concern is how to do that without blocking the event loop—in other words, without blocking FastAPI from handling other requests?
from fastapi import FastAPI
import cassandra_wrapper # Class wrapper providing access to Cassandra database
app = FastAPI()
@app.get("/data")
async def request_data(force=False):
if force:
# perform computations and return data
return cpu_intensive_task()
else:
return cassandra_wrapper.get_data()
# Can call this celery task to do computations
@celery.task(bind=True, name="cpu_intensive_task")
def cpu_intensive_celery_task():
return cpu_intensive_task
# Or can call this function directly to do computations
def cpu_intensive_task():
import time
time.sleep(5)