My Quart app is created with a create_app factory method.
I also have a third party library incorporated as an additional task via the create_task method.
I pass a callback function to this library which updates my database (via SQLAlchemy). Unfortunately this does not work and raises the exception:
"Attempt to access app outside of a relevant context"
Pushing the app context does not work:
from quart import current_app as app
async with app.app_context():
Looking at Quarts Context Documentation: https://pgjones.gitlab.io/quart/contexts.html it is obvious why, because the app does not exist in the third party task.
Both of these contexts exist per request and allow the global proxies current_app, request, etc… to be resolved. Note that these contexts are task local, and hence will not exist if a task is spawned by ensure_future or create_task.
Does anyone has any other solution to get the app context from another task?
Edit It still won't work. I am using Quart 0.10.0. A more verbose example of my app looks like this:
from app import create_app
from third_party import ThirdParty
third_party = ThirdParty(loop=asyncio.get_event_loop())
app = create_app()
@app.before_serving
async def startup():
async with app.app_context() as app_context:
await third_party.start()
@app.after_serving
async def shutdown():
await third_party.stop()
if __name__ == "__main__":
app.run()
The ThirdParty is basically this:
class ThirdParty:
async def start(self):
self.loop.create_task(self.run())
async def run(self):
while True:
await self.wait_for_trigger()
# executes my callback function
await self.custom_callback_func()
my callback function is in another module and I pass to the third_party instance:
from quart import current_app as app
async def custom_callback_func():
async with app.app_context:
# update_my database
# raises "Attempt to access app outside of a relevant context"
If the app_context is automatically copied to created tasks from a task with the app context, why is my example not working?
await third_party.start() inside the with app_context statement calls loop.create_task(run()) which runs my assigned callback function. So why is there no app_context inside this callback available?
I think you must be using a 0.6.X version of Quart? If so the copy_current_app_context
(from quart.ctx) can be used to explicitly copy the context into a new task. For example,
task = asyncio.ensure_future(copy_current_app_context(other_task_function)())
See also this short documentation snippet. Note though that it is written with Quart >= 0.7 which should automatically copy the context between tasks.
Edit: Following an update to the question.
I think you are best placed passing the app
instance and using it directly, rather than using current_app
in the task. This is because there is no app context after before_serving
and before the first request. This may change in Quart though, see this issue.