microsoft / microsoft/vscode-azureresourcegroups

Generated Functions health endpoint hangs when a dependency is down instead of reporting it

Open Beginner friendly
#1,756 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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 / unhealthy branches 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.yml includes postgres and 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 configure retryOptions: { maxTries: 1 } on the BlobServiceClient.
  • Alternatively wrap each check in a shared timeout helper so the pattern is uniform and Promise.all has 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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.