Subchapter 42.43
references/services/functions/consumption-to-flex/windows/automation/trigger-safety-and-monitoring.mdMarkdown12 KBView on GitHub
⚠️ Why this decision exists: When Step 5 deploys code, enabled non-HTTP functions can immediately consume events or run schedules. The risk is highest when 4c copied production settings, 4b reused the source storage account (including implicit bindings), or timer triggers are present. Disabling the target functions before deployment makes cutover controllable in Step 6.
AzureWebJobsStorageHTTP triggers are intentionally left enabled — they don’t pull from a queue, so the new app cannot “steal” HTTP traffic. Clients must be redirected to the new hostname explicitly, which gives you the same safety as disabling.
⚠️ On Linux, a function whose name contains a hyphen (-) cannot be disabled through AzureWebJobs.<FUNCTION_NAME>.Disabled. Never claim that this setting protects a hyphenated function on the Flex target.
Read each deployed function’s trigger binding from the ARM function metadata:
az functionapp function list --name <SOURCE_APP_NAME> --resource-group <SOURCE_RESOURCE_GROUP> --query "[].{name:config.name,triggerType:(config.bindings[?ends_with(type, 'Trigger')] | [0].type)}" -o table💡 Use the alias
triggerType, nottype. Azure CLI’s table formatter suppresses common resource metadata fields namedtype, which can make a valid projection appear blank.⚠️ Skill instruction:
- Reconcile the ARM results with the trigger inventory recorded in the assessment report.
- If ARM genuinely returns a blank, missing, or ambiguous trigger, use source attributes or
function.jsonas the fallback.- If a function remains unresolved, stop — never assume it is event-driven or HTTP.
- Confirm that every deployed function has exactly one classified trigger before presenting the disablement decision.
- Split non-HTTP functions into names that contain
-and names that do not. Record both lists in<UPGRADE_DIR>/upgrade-status.md.
Evaluate these risk factors:
If there are no non-HTTP functions, mark Step 4j skipped — no non-HTTP functions. If settings were deferred, runtime storage and every trigger dependency are isolated from production, no timer or other autonomous function can affect production, and every binding source is resolved, mark Step 4j skipped — target fully isolated. In either case, do not present a disablement prompt or add per-function disable settings; record any hyphenated names and the Linux limitation, then continue to 4k.
If any production-connected non-HTTP function name contains -, do not attempt to disable it on the target. Use ask_user to list the affected functions, explain that they will be active when the Linux target starts, and offer these choices:
Record the selected path and affected function names in <UPGRADE_DIR>/upgrade-status.md. Choices 1 and 2 block deployment until completed. Choice 3 is executed as the transaction in Step 5. Choice 4 requires the same immediate pre-deployment warning and approval as declined disablement.
For the remaining non-HTTP functions whose names do not contain -, use ask_user to list them and summarize the observed risk factors. Strongly recommend disabling all listed functions when any risk factor is present, but leave the decision to the user. Record the choice in <UPGRADE_DIR>/upgrade-status.md.
If the user approves, set a disable flag on the new app for every listed non-HTTP function whose name does not contain - (repeat per function name). Leave HTTP and hyphenated functions unchanged:
az functionapp config appsettings set --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --settings "AzureWebJobs.<FUNCTION_NAME>.Disabled=true" --output noneThe runtime reads these settings at startup, so they are intended to take effect when Step 5 deploys code. Do not call the functions effectively disabled until their runtime state is verified after deployment.
If disablement was approved, verify that the settings were written before moving on:
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "[?starts_with(name, 'AzureWebJobs.') && ends_with(name, '.Disabled')].{name:name, value:value}" -o table⚠️ Skill instruction: If the user approves, apply one
--settingscall per function. Each call triggers a soft-restart but the underlyingMicrosoft.Web/sitesPATCH has a payload limit, so batching dozens into one call can fail. If the source app has more than ~50 functions, write the disable settings to<UPGRADE_DIR>/disabled_functions.json(e.g.[{"name": "AzureWebJobs.FuncA.Disabled", "value": "true"}, ...]) and apply via--settings @<UPGRADE_DIR>/disabled_functions.jsonin a single call. Delete the file immediately after the apply succeeds (it does not contain secrets, but follow the Artifact Output Policy for cleanup hygiene).If the user declines, or selects Deploy active for a hyphenated function, do not write a disable setting for the affected functions. Immediately before Step 5 deployment, use
ask_useragain to warn that the listed functions may consume shared events or run duplicate schedules as soon as deployment completes, then obtain explicit approval to deploy with them enabled.
Microsoft Learn requires monitoring to be enabled before deployment but does not require changing workspaces or authentication models during migration. Preserve the monitoring configuration created or verified by Step 4b unless the user explicitly requests customization.
Restore <TARGET_AI_NAME>, <TARGET_AI_RESOURCE_ID>, and <TARGET_AI_RESOURCE_GROUP> from the verified Step 4b metadata in progress Notes. Require the name and resource group to agree with the component resource ID. Missing or conflicting metadata is a blocker; do not infer the component’s resource group from the function app. Address the component by its full resource ID below so lookups use its own subscription and resource group.
This step verifies that Application Insights is configured and authorized. It does not query telemetry or prove that logs are being ingested; validate runtime behavior and telemetry after code deployment.
Verify the target has an Application Insights connection setting without displaying its value:
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "[?name=='APPLICATIONINSIGHTS_CONNECTION_STRING'].name" -o tsvVerify the Application Insights component recorded from Step 4b:
az monitor app-insights component show --ids <TARGET_AI_RESOURCE_ID> --query "{name:name,id:id,workspaceResourceId:workspaceResourceId}" -o tableRequire the component lookup to succeed and its returned name and resource ID to match the recorded metadata. If either the setting or component is absent, the read fails, or metadata conflicts, stop and investigate. Use ask_user before creating or wiring a replacement monitoring resource. Do not change the selected Log Analytics workspace unless the user explicitly requests monitoring customization.
Check whether the source used AAD-authenticated ingestion:
az functionapp config appsettings list --name <SOURCE_APP_NAME> --resource-group <SOURCE_RESOURCE_GROUP> --query "[?name=='APPLICATIONINSIGHTS_AUTHENTICATION_STRING'].value | [0]" -o tsvIf the value is not Authorization=AAD, keep the target’s platform-created monitoring configuration unchanged. Offer AAD ingestion only as optional post-migration hardening.
If the value is Authorization=AAD, preserve that posture on the target:
az functionapp config appsettings set --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --settings "APPLICATIONINSIGHTS_AUTHENTICATION_STRING=Authorization=AAD" --output noneUse <NEW_PRINCIPAL_ID> from 4e and grant it Monitoring Metrics Publisher on the target Application Insights component:
az role assignment create --assignee-object-id <NEW_PRINCIPAL_ID> --assignee-principal-type ServicePrincipal --role "Monitoring Metrics Publisher" --scope <TARGET_AI_RESOURCE_ID>Verify setting names and the target-scoped role without displaying connection-string values:
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "[?starts_with(name, 'APPLICATIONINSIGHTS_')].name" -o tsvaz role assignment list --assignee-object-id <NEW_PRINCIPAL_ID> --scope <TARGET_AI_RESOURCE_ID> --query "[?roleDefinitionName=='Monitoring Metrics Publisher'].{role:roleDefinitionName,scope:scope}" -o tableVerify the new app exists and is configured:
az functionapp show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "{name:name, kind:kind, sku:properties.sku}" --output tableReview target app-setting names:
az functionapp config appsettings list --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --query "[].name" -o tsvCheck managed identity:
az functionapp identity show --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP>Check custom domains:
az functionapp config hostname list --webapp-name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --output tableThese are not handled by Steps 4a–4i and require manual configuration:
If Step 2e identified certificates used by the source app, re-add only those certificates using the documented site-scoped certificate process (opens in a new tab). Confirm the target remains within the limit of three private and three public certificates.
WEBSITE_LOAD_CERTIFICATES is not used by Flex Consumption. Make each required certificate accessible to app code through the documented process, and update code that used the Windows certificate store to load from /var/ssl/certs for public certificates or /var/ssl/private for private certificates.
Use the WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT value collected in Step 3a as <MAX_SCALE_SETTING>. If the source setting was absent, keep the target default and skip this command. If it was set, confirm the value is within the Flex Consumption range of 1–1000 before applying it:
az functionapp scale config set --name <NEW_APP_NAME> --resource-group <RESOURCE_GROUP> --maximum-instance-count <MAX_SCALE_SETTING>⚠️ Reducing below 40 for HTTP apps can cause frequent request failures.