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.

Possible to execute a function after returning a response inside a route?

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from 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")

Description

I 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 System

Linux

Operating System Details

No response

FastAPI Version

0.65.1

Python Version

3.9.8

Additional Context

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10

github_iconTop GitHub Comments

1reaction
jacksboxcommented, Mar 17, 2022

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

0reactions
coltonbhcommented, Mar 24, 2022

@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 BackgroundTask does this perfectly. If the request is prematurely terminated by the client (say for a connection issue, or timeout) the BackgroundTask does not execute. And the BackgroundTask does not start execution until after the successful return of the response. The following code show a working example:

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 ctrl + c while the response is in flight.

@yinziyan1206 Thanks for the suggestions on the middleware. The middleware doesn’t follow the same paradigm for execution: the finally clause will execute no matter the success/failure of the request and middleware appears to not support try/except/else/finally clauses beyond try/finally. Here’s an example that demonstrates this:

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 httpx client you will never reach the else or except blocks of the middleware. However the finally block will always execute after a request, so this seems like a great way to cleanup any state that is associated with a request; however, it cannot trigger different behaviors for when a request succeeds and when it fails. Let me know if I’m missing anything here and thank you for your thoughtful feedback and suggestions.

The BackgroundTask meets the specs I was looking for:

  1. Execute if request is successful
  2. Do not execute if request fails due to client-side termination or connection issues (not just server-side exceptions).

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!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Execute a function after Flask returns response - Stack Overflow
I just tested again by adding a time.sleep call followed by print in the call_on_close handler. It distinctly runs after the response has...
Read more >
Routing & Input - R Plumber
Plumber's first job is to execute R code in response to incoming HTTP requests ... the function will be used as the response...
Read more >
Call functions via HTTP requests | Cloud Functions for Firebase
You can trigger a function through an HTTP request by using functions.https . This allows you to invoke a synchronous function through the...
Read more >
Python developer reference for Azure Functions
Understand how to develop functions with Python.
Read more >
API Reference - Express 4.x
This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser. Returns middleware that...
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