Azure / Azure/azure-functions-python-worker
Support async startup and shutdown lifecycle hooks for Python Function Apps
- Dominant language
- Python
- Stars
- 357
- Forks
- 116
- Avg merge
- 32m
- Merged PRs (30d)
- 1
Description
### Binding Type
Not binding-specific. This is a Python worker / Python v2 programming-model lifecycle capability for any Function App that owns process-scoped async resources.
### Expected Behavior
Provide supported worker-process startup and shutdown hooks that Python applications and libraries can register through the v2 `FunctionApp` programming model.
The shutdown callback should:
- run once per Python language-worker process during graceful host shutdown, local `func stop`, and scale-in;
- execute on the worker's active asyncio event loop so async SDK clients can be awaited safely;
- define ordering, timeout, cancellation, and exception-handling semantics;
- not run concurrently with new invocations after shutdown begins;
- work consistently for `FunctionApp` and Durable `DFApp` applications;
- remain process-local when `FUNCTIONS_WORKER_PROCESS_COUNT` or scale-out creates multiple workers.
This enables deterministic cleanup of module-level/shared Azure SDK clients while following Azure Functions guidance to reuse SDK client instances across invocations.
### Relevant sample code snipped
```python
import azure.functions as func
app = func.FunctionApp()
@app.on_startup
async def startup() -> None:
await resources.initialize()
@app.on_shutdown
async def shutdown() -> None:
await resources.close()
```
The exact API shape is open for discussion; a registration API or worker-extension lifecycle contract would also satisfy the requirement.
### Additional Information
Azure Functions recommends sharing SDK clients across invocations to reduce latency, socket exhaustion, and SNAT pressure:
https://learn.microsoft.com/azure/azure-functions/manage-connections#manage-sdk-client-connections
Today `FunctionApp` and `DFApp` do not expose a supported async shutdown hook. Libraries must choose between per-invocation client churn, process-lifetime clients without deterministic cleanup, or fragile `atexit`/signal handling that may run after the event loop is unavailable.
A concrete example is Azure/azure-functions-agents-runtime#157 and its proposed fix in Azure/azure-functions-agents-runtime#158. Microsoft Foundry clients own both async httpx and aiohttp transports. Sharing these clients fixes steady-state connection churn, but deterministic graceful shutdown cannot be integrated safely without a worker lifecycle hook.
Suggested acceptance coverage:
- async callback executes on the worker event loop;
- exactly once per process for graceful stop and scale-in;
- callback completion is bounded by a documented timeout;
- callback errors are logged without skipping other registered callbacks;
- no new invocation begins after shutdown callbacks start;
- Core Tools integration test covers `func start` followed by graceful stop;
- multiple worker processes each invoke their own callbacks.
Contributor guide
Research direction
Begin with the Python v2 FunctionApp and Durable DFApp registration paths and the worker shutdown lifecycle. Check the proposed Core Tools graceful-stop integration scenario against the acceptance points: event-loop execution, one callback per process, bounded completion, error isolation, and no new invocations after shutdown starts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100