microsoft / microsoft/vscode-azureresourcegroups
Generated Functions health endpoint hangs when a dependency is down instead of reporting it
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 78
- Forks
- 55
- Avg merge
- 16h 49m
- Merged PRs (30d)
- 139
Description
What happened
The scaffold agent generated an Azure Functions health endpoint that hangs indefinitely when a dependency is unavailable, instead of reporting the dependency as down.
Caught by the runtime-health eval gate in MSBench run 2026082875609243, the first run in which the runtime gates executed against a running application.
The Functions host registers the route and begins executing it:
Functions:
health: [GET] http://localhost:7071/api/health
[2026-08-28T21:16:16.663Z] Executing 'Functions.health' (Reason='This function was programmatically called via the host APIs.', Id=1c5999c7-…)
There is no matching Executed 'Functions.health' (Succeeded, …) line. The probe gave up after its 10s budget:
[healthEndpointUnreachable] /api/health: the app is listening on http://127.0.0.1:7071
but the health endpoint /api/health (declared in .azure/integration-plan.md) could not
be reached: The operation was aborted due to timeout.
Root cause
services/functions/src/functions/health.ts fans out to both dependencies and waits for both:
const [databaseHealth, storageHealth] = await Promise.all([
services.database.healthCheck(),
services.storage.healthCheck(),
]);
The two checks are not written to the same standard:
| Dependency | Implementation | Behaviour with no server |
|---|---|---|
| PostgreSQL | new Pool({ …, connectionTimeoutMillis: 2000 }), pool.query('SELECT 1') in try/catch |
fails in ~2s, returns { status: 'down' } — correct |
| Blob Storage | containerClient.exists() in try/catch, no timeout or retry options |
@azure/storage-blob applies its default retry policy (multiple attempts with exponential backoff), far exceeding the probe budget |
Promise.all resolves at the pace of the slowest branch, so the unbounded storage check determines the endpoint's latency. The try/catch does not help: it catches a rejection, and the SDK has not rejected yet — it is still retrying.
Why it matters
- The handler has
healthy/degraded/unhealthybranches and a 503 path that can never be reached when a dependency is hard-down, which is exactly when they matter. - Azure health probes (App Service, Container Apps, Front Door) treat a timeout as a failure with no diagnostic. A 503 carrying
{ database: down, storage: down }is actionable; a hang is not. - The generated
docker-compose.ymlincludespostgresand Azurite, so this reproduces whenever a developer runs the API without first starting compose — a normal thing to do.
Suggested fix
Bound every dependency check, so a hung dependency degrades the response rather than the endpoint:
- Pass an abort signal / timeout to the storage call, e.g.
containerClient.exists({ abortSignal: AbortSignal.timeout(2000) }), and/or configureretryOptions: { maxTries: 1 }on theBlobServiceClient. - Alternatively wrap each check in a shared timeout helper so the pattern is uniform and
Promise.allhas a bounded worst case.
The database check is already the right shape and can serve as the model.
Notes
This is a product/agent-output defect, not a harness one. The eval also surfaced a separate portEnvironmentVariableIgnored finding on the same run, which was a harness false positive for Functions projects and has been fixed under PR #1755.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in services/functions/src/functions/health.ts and compare the storage health check with the PostgreSQL check, using the runtime-health eval and /api/health behavior as the feedback loop. Bound the storage or shared dependency check so an unavailable service returns a degraded or unhealthy response, including the dependency status, instead of exceeding the probe timeout.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, postgresql, typescript
- Domain
- api, backend, cloud
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100