This check flags Azure App Services where Always-On is disabled, which lets the platform unload your app after 20 minutes of inactivity. That causes cold starts, broken background jobs, and missed scheduled triggers. Fix it by setting --always-on true on the app's site config.
An idle Azure App Service is not a free win. When Always-On is turned off, the platform happily evicts your worker process to reclaim resources, and the next request pays the price with a slow, cold restart. For internal tools that might be acceptable. For anything customer facing, or anything running background work, it quietly breaks things in ways that are hard to debug.
This Lensix check, appservice_alwayson in the appservice_checks module, looks at each Azure App Service and reports the ones running without Always-On enabled.
What this check detects
Azure App Service has a per-app setting called Always On. When it is off (the default on many tiers), the App Service platform will unload your application after roughly 20 minutes with no inbound traffic. The next request triggers a cold start: the worker spins back up, your runtime initializes, dependencies reconnect, and the user waits.
The check inspects the site configuration of each App Service in scope and flags any where alwaysOn is set to false.
Note: Always-On works by having the platform send a periodic internal request to the app's root path, which keeps the worker process warm. It does not generate external traffic and does not bypass your authentication, since the request originates inside the App Service infrastructure.
Why it matters
The impact depends on what your app does, but the failure modes fall into a few clear buckets.
Cold starts hurt user-facing latency
After the app unloads, the first request can take several seconds to respond while the runtime warms up. A .NET app reloading assemblies, a Node app rebuilding its module cache, or a Java app starting the JVM all add measurable delay. If your traffic is bursty or you have quiet periods overnight, real users hit these cold starts regularly.
Background jobs and continuous WebJobs stop running
This is the one that catches teams out. Continuous WebJobs and many in-process background workers only run while the app is loaded. If the app unloads because nobody hit it, your background processing stops too. Queue consumers stall, retry loops freeze, and work silently piles up.
Warning: Continuous WebJobs require Always-On to run reliably. Without it, the worker is evicted during idle periods and your jobs simply stop processing until the next inbound request wakes the app back up.
Scheduled triggers misfire
Timer-based functionality hosted in App Service, including older Functions running in an in-process model on a dedicated plan, depends on the app being loaded to fire on schedule. An evicted app can miss its window entirely, so a job you think runs every five minutes might skip an hour because nobody visited the site.
Health probes and monitoring give false signals
External uptime checks that hit your app infrequently can record inflated response times caused purely by cold starts, not by genuine performance problems. You end up chasing latency ghosts that disappear the moment traffic picks up.
How to fix it
Always-On is a single boolean. The harder part is making sure you apply it everywhere and that it stays applied.
Warning: Always-On is only available on Basic tier and above. On Free and Shared (F1/D1) plans the setting is unavailable, because those tiers do not guarantee a dedicated worker. If your app needs Always-On, you may need to scale up to at least a Basic (B1) plan, which has a cost implication.
Azure Portal
- Open the App Service in the Azure Portal.
- Go to Settings → Configuration.
- Select the General settings tab.
- Set Always on to On.
- Click Save. The app restarts to apply the change.
Azure CLI
Set it directly on the app's web config:
az webapp config set \
--resource-group myResourceGroup \
--name myAppService \
--always-on true
Confirm it took effect:
az webapp config show \
--resource-group myResourceGroup \
--name myAppService \
--query "alwaysOn"
A return value of true means the setting is applied.
Note: For deployment slots, Always-On is configured per slot. A production slot with Always-On enabled does not automatically pass that setting to a staging slot. Set it explicitly on every slot you care about.
To set it on a specific slot:
az webapp config set \
--resource-group myResourceGroup \
--name myAppService \
--slot staging \
--always-on true
Terraform
For the modern azurerm_linux_web_app or azurerm_windows_web_app resource, set it inside the site_config block:
resource "azurerm_linux_web_app" "example" {
name = "my-app-service"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
service_plan_id = azurerm_service_plan.example.id
site_config {
always_on = true
}
}
Bicep
resource appService 'Microsoft.Web/sites@2023-01-01' = {
name: 'my-app-service'
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
alwaysOn: true
}
}
}
Tip: If you manage infrastructure with Terraform or Bicep, fix this in code rather than the portal. A portal change gets overwritten the next time your pipeline applies the template, so manual fixes on IaC-managed apps tend to silently regress.
How to prevent it from happening again
One-off fixes drift. The goal is to make Always-On the default and to catch any app that ships without it.
Enforce with Azure Policy
Azure Policy can audit, or deny, App Services that do not have Always-On enabled. A custom policy definition keyed on the alwaysOn site config field works well:
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Web/sites"
},
{
"field": "Microsoft.Web/sites/siteConfig.alwaysOn",
"notEquals": true
}
]
},
"then": {
"effect": "audit"
}
}
Start with the audit effect so you can see existing offenders without breaking deployments. Once your estate is clean, switch the effect to deny to block new non-compliant apps at create time.
Warning: A deny policy will also block Free and Shared tier apps, since they cannot enable Always-On at all. Scope the policy to exclude those tiers, or exempt the specific resource groups where low-tier apps are intentional.
Add a CI/CD gate
If you deploy through pipelines, scan your IaC before it reaches Azure. A simple check in your pipeline can reject any Terraform plan or Bicep file where always_on is missing or false. Tools like Checkov and tfsec ship rules for this, and you can wire them into a pull request check so the fix happens in review, not in production.
Run continuous checks with Lensix
Policy and pipeline gates cover new resources. Lensix runs appservice_alwayson across your existing estate on an ongoing basis, so apps that were created before your guardrails existed, or changed by hand, still surface. That closes the gap between point-in-time deployment checks and live configuration.
Best practices
- Enable Always-On on anything with background work. If your app runs continuous WebJobs, timers, queue consumers, or in-process schedulers, Always-On is not optional.
- Use the right tier for the workload. If you need Always-On, you need at least a Basic plan. Do not try to run production background jobs on Free or Shared tiers.
- Set it on every slot. Staging and pre-production slots are easy to forget, and a cold staging slot leads to misleading test results.
- Manage the setting in IaC. Keeping
always_onin Terraform or Bicep makes it reviewable, versioned, and resistant to drift. - Consider Functions or Container Apps for spiky workloads. If your real problem is scaling to zero gracefully, a consumption-based Function or Container App may fit better than paying to keep an App Service worker warm around the clock.
- Pair Always-On with a real health check path. Configure a lightweight health endpoint so the keep-alive request and your monitoring both hit something cheap rather than your homepage.
Always-On is a small setting with an outsized effect on reliability. Turn it on where it matters, enforce it in code, and let continuous checks catch the apps that slip through.

