Azure / Azure/functions-action

Deploying to Flex Consumption plans only displays "WarmUp" in Portal, requires clicking "Refresh" to see my function names

Open
#373 1 comment 0 reactions 0 assignees View on GitHub
need-to-triage
Dominant language
TypeScript
Stars
184
Forks
92
PR merge metrics
No merged PRs in 30d

Description

# Summary

When I deploy my Azure Functions app to a Flex Consumption plan using `Azure/functions-action`, Azure Portal only displays `WarmUp` in the Functions list on the overview blade. I have to click `Refresh` in order to see my actual functions.

# Environment

- **Action version:** `Azure/functions-action@v1.5.6` (pinned to `bc63708cc6539760eea18d8a7de4ce8ef5fdf593`)
- **Plan:** Azure Functions **Flex Consumption**
- **Runtime:** .NET 10, isolated worker model, self-contained, `linux-x64`
- **Deploy method:** zip package built via `dotnet publish`, uploaded via the action's `package` input (see workflow excerpt below)
- **CI:** GitHub Actions (`ubuntu-latest`), authenticating via OIDC (`azure/login`)

# Expected Behavior

After a successful deployment, in Azure Portal, I see a list of my functions, available and ready to run.

# Actual Behavior

After a successful deployment, in Azure Portal, I see only `WarmUp`, which is not one of my functions. I have to click `Refresh`, after which I see my functions, and they're available and ready to run.

# What I have tried

With Claude's help, I tried the following:

1. **Baseline:** rely solely on `Azure/functions-action`'s built-in deployment + Kudu sync. It almost always results in only `WarmUp` being display in Azure Portal.
1. **`az functionapp restart` immediately after deploy.** Theory: force re-specialization of a worker so it picks up the new package. Did not reliably resolve it (and risks restarting mid-async-deployment-pipeline, since Kudu's pipeline can still be finishing up to ~60s after the "Finished deployment pipeline" log line).
1. **Call the ARM `host/default/sync` endpoint** (the same one the Portal's **Refresh** button calls) after a fixed `Start-Sleep -Seconds 90`:
```powershell
az rest --method post --url "https://management.azure.com/subscriptions//resourceGroups//providers/Microsoft.Web/sites//host/default/sync?api-version=2018-11-01"
```
This worked on the very next deployment after adding it, then reverted to showing `WarmUp` on a subsequent deployment with no other changes — suggesting the fixed 90s delay is a race rather than a real fix: Flex Consumption instance specialization time (cold start, loading the app + native dependencies) is variable, and a single fire-and-forget sync call issued too early has nothing real to report yet.
1. **Current workaround:** replaced the single sync call with a poll loop — call `host/default/sync`, then `GET .../functions` and check for a known function name, retrying with backoff (up to ~10 attempts / ~7 minutes) before failing the CI job loudly if it never resolves. This makes the failure *visible* in CI instead of silently leaving a stale Portal, but it's a workaround for what still looks like a platform/action reliability gap, not a fix.

# Relevant workflow excerpt with workaround

So far, this workaround has resulted in the expected behavior after every deployment:

```yaml
- name: Deploy ZIPped Function with the Azure Functions Action
uses: Azure/functions-action@bc63708cc6539760eea18d8a7de4ce8ef5fdf593 # v1.5.6
with:
app-name: ${{env.FUNCTION_APP_NAME}}
package: ${{env.PUBLISH_ZIP_FILE_NAME}}

# Kudu's own SyncTriggerStep (visible in App Insights) calls hostruntime/admin/host/synctriggers,
# which isn't reliably picked up by the Portal/runtime on Flex Consumption. The Portal's Refresh
# button, which does work, calls the ARM-level host/default/sync endpoint instead - call that
# same endpoint here.
#
# A single sync call on a fixed delay is a race: on Flex Consumption an instance has to cold-start
# and specialize with the new package (including native Magick.NET/SkiaSharp deps) before sync has
# anything real to report, and that takes a variable amount of time. Until it does, sync/Portal keep
# showing the placeholder WarmUp function. So poll: call sync, then check whether CheckAlertsScheduled
# is actually registered, and retry with backoff until it is (or we give up and fail the job loudly
# instead of silently leaving WarmUp behind).
- name: Sync triggers and verify the deployment took effect
run: |
$resourceGroup = az functionapp list --query "[?name=='${{env.FUNCTION_APP_NAME}}'].resourceGroup" -o tsv
$syncUrl = "https://management.azure.com/subscriptions/${{vars.AZURE_SUBSCRIPTION_ID}}/resourceGroups/$resourceGroup/providers/Microsoft.Web/sites/${{env.FUNCTION_APP_NAME}}/host/default/sync?api-version=2018-11-01"
$listUrl = "https://management.azure.com/subscriptions/${{vars.AZURE_SUBSCRIPTION_ID}}/resourceGroups/$resourceGroup/providers/Microsoft.Web/sites/${{env.FUNCTION_APP_NAME}}/functions?api-version=2023-12-01"

$maxAttempts = 10
$delaySeconds = 30
$verified = $false

for ($attempt = 1; $attempt -le $maxAttempts; $attempt++) {
Write-Output "Attempt $attempt/$maxAttempts - waiting ${delaySeconds}s before syncing triggers..."
Start-Sleep -Seconds $delaySeconds

az rest --method post --url $syncUrl | Out-Null

# Give the sync call a moment to propagate before checking what it reported.
Start-Sleep -Seconds 10

$functionNames = az rest --method get --url $listUrl --query "value[].name" -o tsv
Write-Output "Functions currently known to the runtime:`n$functionNames"

if ($functionNames -match 'CheckAlertsScheduled') {
Write-Output "Verified CheckAlertsScheduled is registered - deployment took effect."
$verified = $true
break
}
}

if (-not $verified) {
Write-Error "Trigger sync did not pick up CheckAlertsScheduled after $maxAttempts attempts (~$($maxAttempts * ($delaySeconds + 10))s). The Function App may still be serving the WarmUp placeholder - check the Portal and consider a manual restart."
exit 1
}

```

# Related issue

It looks like this was fixed for `Consumption` plans in [#135](https://github.com/Azure/functions-action/issues/135) ("triggers not synced after deployment," classic Consumption plan, closed August 2022) by pull request [#148](https://github.com/Azure/functions-action/pull/148).

# Question

- Is it possible for this action to handle this polling and checking internally?
- Claude suggests that perhaps the fix from [#135](https://github.com/Azure/functions-action/issues/135) for Consumption plans can also be applied for `One Deploy` deployments to Flex Consumption plans. Is that possible?

# Note

This also happens with the stock Azure DevOps Pipelines `AzureFunctionsApp@v2`: https://github.com/microsoft/azure-pipelines-tasks/issues/22354

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing the trigger-sync behavior associated with the deployment path and compare it with the fix in issues #135 and pull request #148. Reproduce the Flex Consumption case using the documented host/default/sync and functions endpoints; done means the action reliably exposes the deployed functions without a manual Portal refresh.

Written by the indexing model from the issue text.

Assessment

Tech stack
azure, github-actions, typescript
Domain
cloud, devops
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.