-
First Check
Commit to Help
Example Codefrom fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
try:
return {"message": "Hello World"}
except Exception:
pass
else:
print("I'm executing after successfully returning a response")
finally:
print("I'm executing after a successful or failed response")DescriptionI would like to execute a particular action after a response has been successfully returned. My use case is that the end user attempts to retrieve an object via FastAPI from my in memory database. Only if the response succeeds, then I'd like to remove the object from the database. I only want to remove the item after successfully returning a response, as responses may fail due to idiosyncrasies in the user's connection. Is there a "FastAPI" way to do this? It seems straightforward but I can't find anything related to this in the documentation after searching the docs for the words "finally" and "except". If there's not a "FastAPI" way to do this, any other more general approach to achieve this you might recommend? Much thanks! 🙏🏼 Operating SystemLinux Operating System DetailsNo response FastAPI Version0.65.1 Python Version3.9.8 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 14 comments 1 reply
-
|
add BaseHTTPMiddleware or using exception handler |
Beta Was this translation helpful? Give feedback.
-
|
you can use Background Tasks for this - https://fastapi.tiangolo.com/tutorial/background-tasks/ - they do exactly what you require - execute code just after successful return |
Beta Was this translation helpful? Give feedback.
-
@jacksbox wouldn't this create a race condition? I kick off the background task before returning the response, the background task will likely complete quickly (it's just an in memory DB delete) and the response may fail a few seconds after the fact? @yinziyan1206 I'll take a look at these objects! It appeared the exception handler would only execute if an exception were raised inside the response function, correct? And thank you both for your responses! |
Beta Was this translation helpful? Give feedback.
-
|
@yinziyan1206 it appears middleware cannot solve the problem:
https://fastapi.tiangolo.com/tutorial/middleware/?h=middlewa#middleware |
Beta Was this translation helpful? Give feedback.
-
|
Yes, you can use exception handler to do some something when catching exception. And middleware is like a decorator, or a wrapper when receiving request. You can handle a request or the response, like making a wrapper for call_next(Request) |
Beta Was this translation helpful? Give feedback.
-
|
@yinziyan1206 do you know what exception is raised if a client connection is cut before the full response has returned? This would be helpful. It appears from the docs that the middleware only operates before returning a response. I.e., I can operate on the response object and then return it to the end user. However, I'd like to execute code after successfully returning a response to the client app. I do not want to delete the data from my DB before knowing it has been successfully returned to the end user. I'm looking at these docs to come to this conclusions: |
Beta Was this translation helpful? Give feedback.
-
|
@coltonbh according to the fastapi docs (and the starelette docs, the underlying implementation https://www.starlette.io/background/) background tasks get only executed after the response is send to the client - if there is an exception somewhere inside the fastapi app, the task does not execute... Or do you really want to check if a response arrives at the client? the only way to do that is on the client I guess... |
Beta Was this translation helpful? Give feedback.
-
@coltonbh That's right. And you can try this example. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for your responses! Will have a second to play with this later this week and try it out :) Will report back! |
Beta Was this translation helpful? Give feedback.
-
|
@jacksbox yes I'd like to really check that the response arrives at the client! Otherwise I won't want to delete the data they are requesting. Turns out the from time import sleep
from fastapi import FastAPI, BackgroundTasks, Request
app = FastAPI()
def delete_objects(filename: str):
print(f"Deleting: {filename}")
@app.get("/")
async def root(background_tasks: BackgroundTasks):
sleep(3)
background_tasks.add_task(delete_objects, "my filename")
return {"hello": "world"}And on the client side: import httpx
# Response is returned and the background task will execute
r = httpx.get("http://localhost:8000", timeout=5)
# Response not returned due to client termination and the background task will not execute
r = httpx.get("http://localhost:8000", timeout=2)The same correct behavior will occur is the client manually terminates the connection with a @yinziyan1206 Thanks for the suggestions on the middleware. The middleware doesn't follow the same paradigm for execution: the from time import sleep
from fastapi import FastAPI, BackgroundTasks, Request
app = FastAPI()
@app.middleware("http")
async def middleware(request: Request, call_next):
try:
print("in try")
return await call_next(request)
except Exception:
print("Don't delete the file because the client did not get it!")
else:
print("Delete the file!")
finally:
print("In finally!")
@app.get("/")
async def root(background_tasks: BackgroundTasks):
sleep(3)
return {"hello": "world"}If you do the same requests noted above with the The
If I've inaccurately summarized your suggestions or findings please let me know and I'll update my response. Thanks to you both very much! |
Beta Was this translation helpful? Give feedback.
-
|
Thank you for providing the example but upon trying it myself I noticed it doesn't really work i.e. the background task is indeed ran twice. Do you maybe spot anything different I might have copied wrong? |
Beta Was this translation helpful? Give feedback.
-
|
Oooof. @besarthoxhaj you're right! I'm not sure why I was so confident this worked before--I even tried with the same older ( Perhaps there is no way to know that the request has truly succeeded? It appears both the |
Beta Was this translation helpful? Give feedback.
-
|
@coltonbh I might have a look later and see if I can help |
Beta Was this translation helpful? Give feedback.
-
|
I was also looking for this but... upon further reflection, isn't it just much better to let the client do another request after the client knows it has successfully received and processed the first query? After all, if we want to make sure the client has successfully been given the content of a request, how do we know that the request hasn't been successfully received by the client but then the client died before it could do what it needed to do? The server simply can't know that... unless the client tells it. So unless there is some ridiculous clause the lawyers put in referring to tcp acks being received that the data was "sent" (so we get our $$$), I'm not so sure I see this as a valid usecase anymore... |
Beta Was this translation helpful? Give feedback.


you can use Background Tasks for this - https://fastapi.tiangolo.com/tutorial/background-tasks/ - they do exactly what you require - execute code just after successful return