ants-azure-demos
ants-azure-demos copied to clipboard
Startup and shutdown events not triggered
Hi, and first of all thank you for your work ! I'm currently working on a webapp hosted on Azure and wanted to go serverless; your AsgiMiddleware was a huge help. However I'm trying to use with with a FastAPI app where I instantiate a MongoClient at the startup of the app (much like here : https://github.com/markqiu/fastapi-mongodb-realworld-example-app/tree/master/app). When I publish my function and test it, the Mongo client doesnt seem to be set. Maybe because the startup events of the app are never triggered ? Do you have any idea on how I could make this work ? Thanks !
Hmm, I don't know if that would be possible since in the serverless/functions model there isn't really a startup event and the function state isn't persistent. Even if there were a workaround, it'll likely be really slow.
Your best bet I think would be to put this in a container and run the container to Web Apps
Here's an example GitHub Actions script https://github.com/tonybaloney/try-pyjion/blob/main/.github/workflows/azure-container-webapp.yml
Please let me know if this works for you
Thanks for your answer ! I'm currently running the app in a container in a WebApp and it works just fine. However I wanted to leverage the scaling capabilities of serverless functions. The fact that the model isnt persistent got me doubting it was a viable solution at first, but Azure best practices recommends reusing static clients in functions invocations (https://docs.microsoft.com/en-us/azure/azure-functions/manage-connections?tabs=csharp). This seems to indicate that I could startup the app once and persist it across functions calls. I found this useful post : https://github.com/Azure/azure-functions-python-worker/issues/911. I had to fix some asyncio loops shenanigans with nest_asyncio for everything to run on Azure functions. I does feel "workaround-y" but the following code seems to be working. Any thoughts ?
import azure.functions as func
from app.main import app
from azure.functions._http_asgi import AsgiResponse, AsgiRequest
import nest_asyncio
IS_INITED = False
nest_asyncio.apply()
async def run_setup(app):
"""Workaround to run Starlette startup events on Azure Function Workers."""
global IS_INITED
if not IS_INITED:
await app.router.startup()
IS_INITED = True
async def handle_asgi_request(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
asgi_request = AsgiRequest(req, context)
scope = asgi_request.to_asgi_http_scope()
asgi_response = await AsgiResponse.from_app(app, scope, req.get_body())
return asgi_response.to_func_response()
async def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
await run_setup(app)
return await handle_asgi_request(req, context)
@MrToustous and @tonybaloney I also faced the same issue @tonybaloney Your Above Answer about startup events in serverless helped me to find the problem Thanks a lot for that
Here's How I Fixed This Issue But I am not sure about the drawback of this method because I don't have much knowledge about the async world in Python, I would love to know in which cases this code can break
connection_string = os.environ["DCS"]
logging.info(f"connection string {connection_string}")
async def init():
client = AsyncIOMotorClient(connection_string)
await init_beanie(database=client['Tradex'],document_models=[Admin,User])
loop = asyncio.get_running_loop()
asyncio.set_event_loop(loop)
loop.create_task(init())
I've got a PR to the Azure Functions library to add support for startup and shutdown events in ASGI applications. If you need this feature ASAP, you could install the library directly from the branch by modifying requirements.txt
and pointing to the branch URL, then using this environment variable
https://github.com/Azure/azure-functions-python-library/pull/187
@tonybaloney I was unaware of this PR Thanks a lot 👍🏻