Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intended behavior on BackgroundTasks #56

Closed
hhamana opened this issue Nov 20, 2021 · 2 comments
Closed

Intended behavior on BackgroundTasks #56

hhamana opened this issue Nov 20, 2021 · 2 comments
Labels
question Further information is requested

Comments

@hhamana
Copy link
Collaborator

hhamana commented Nov 20, 2021

I have fairly recently found a point of confusion, that I cannot explain to myself.
Starlette (and FastApi by extension) provide a BackgroundTask feature, which allows one to do further processing after a request has been sent.
I was expecting this to be incompatible with the context provided by starlette_context, as the middleware explicitly resets the context before sending the response, leading to the You didn't use the required middleware or you're trying to access `context` object outside of the request-response cycle. error. The background task is ran after the response, therefore is out the that cycle.
However, this is not what happens. The context can be accessed within a background task. It does not error, and can access the appropriate context data from the request that spawned it.
The response is returned with correct headers, indicating the middleware does indeed process the response, and the background task is very much processed after that. I haven't seen any confusion of data between concurrent requests either.
It's all good, but I don't understand how.

@hhamana hhamana added the question Further information is requested label Nov 20, 2021
@tomwojcik
Copy link
Owner

tomwojcik commented Nov 21, 2021

I haven't been using any asgi for over a year now but if I had to guess - background tasks are not as background as it seems. They still run within the request-response cycle. They are initialized just after the response has been sent (asynchronously). It's the same event loop, so "the context of the context" will be available. If one of these tasks was doing some computation ( or time.sleep(5)) your worker would be blocked as its event loop would be blocked.

https://github.com/encode/starlette/blob/881af38cc2e038de1f02e4fba7b7dab2df79b38a/starlette/responses.py#L148-L159

If I understand it correctly, response.__call__ is exactly what self.app(scope, receive, send_wrapper) is doing, so the context hasn't been reset yet.

try:
await self.app(scope, receive, send_wrapper)
finally:
_request_scope_context_storage.reset(token)

So yeah, although surprising, it makes sense.

@hhamana
Copy link
Collaborator Author

hhamana commented Nov 22, 2021

ooh, I see. The background task is processed right after, literally the next line after the response is sent, which as seen from the middleware, is still in the try block. the reset is only after, in the finally block, which ends up executed after the response AND the background task.
I understand now, and feel I can sleep soundly again.

@hhamana hhamana closed this as completed Nov 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants