Azure / Azure/azure-functions-host

Linux Consumption Plan: Silent worker crashes, no diagnostic logging, unreliable Service Bus triggers (Node.js v4 + Prisma)

Open
#11,677 1 comment 1 reaction 1 assignee Claimed by @RohitRanjanMS View on GitHub
Needs: Triage (Functions)
Dominant language
C#
Stars
2k
Forks
482
Avg merge
2d 10h
Merged PRs (30d)
36

Description

# Azure Functions Linux Consumption Plan — Feedback Report

**Date:** 2026-03-30
**Submitted by:** manohar.madhira@outlook.com
**Product:** Azure Functions (Linux Consumption Plan, Node.js v4 Programming Model)
**Severity:** Service-impacting — forced architecture change away from Azure Functions
**Subscription:** 587c0dc1-a525-4ac5-95b2-de11410eb481
**Function App:** artistos-functions (East US)

---

## Summary

We were unable to reliably run an Azure Function (Node.js, v4 programming model, Service Bus trigger) on the Linux Consumption Plan. After two days of debugging — including multiple clean deploys, function app recreation, SDK version pinning, and dozens of configuration changes — we abandoned Azure Functions and moved the workload into our Azure Container App.

---

## Environment

| Component | Version |
|---|---|
| Azure Functions Runtime | v4 |
| Node.js | 20 (also tried 22) |
| `@azure/functions` SDK | 4.5.1 (also tried 4.12.0) |
| OS | Linux |
| Plan | Consumption |
| Trigger | Service Bus Queue (`serviceBusQueue()` v4 API) |
| ORM | Prisma 5.22.0 (with `linux-musl-openssl-3.0.x` binary target) |
| Region | East US |

---

## What We Were Building

A Service Bus-triggered function that:
1. Receives a message with a `releaseId`
2. Loads release data from PostgreSQL (via Prisma)
3. Calls the Claude API to generate a marketing plan
4. Writes the plan back to PostgreSQL
5. Updates the release status

This is a straightforward async worker pattern. The function was initially deployed successfully via `release.sh` (first deploy showed both triggers registered). Subsequent deploys broke it.

---

## Issues Encountered

### Issue 1: `func` CLI respects `.gitignore`, excluding `dist/`

**Problem:** Our project's root `.gitignore` includes `dist/`. The `func azure functionapp publish` command respects `.gitignore` and silently excludes the `dist/index.js` compiled output — the function's entry point (`"main": "dist/index.js"` in package.json).

**Result:** Function deployed with no entry point. Host starts but finds no functions. No error reported during deploy — trigger sync just shows empty function list.

**Workaround:** Created `.funcignore` to override `.gitignore` exclusions.

**Suggestion:** The `func` CLI should warn when the `main` entry point specified in `package.json` is excluded from the deployment package.

### Issue 2: Windows-built Prisma binaries fail silently on Linux

**Problem:** When deploying from a Windows development machine, `npm install` generates Windows Prisma query engine binaries. Despite `binaryTargets = ["native", "linux-musl-openssl-3.0.x"]` in the Prisma schema, the Linux binary is placed in `node_modules/.cache/prisma/` (not the primary client location). On the Linux consumption plan, the function crashes at startup with a 502 BadGateway.

**Result:** Worker process crashes. No logs in Application Insights. No error in deploy output. Host returns 502 on all requests. Service Bus messages sit in queue indefinitely.

**Workaround:** Used `--build remote` flag to build on Azure's Linux environment. Required moving the TypeScript build into the `postinstall` script so the remote build compiles everything server-side.

**Suggestion:** The Azure Functions runtime should log clear errors when Prisma (or any native module) fails to load, rather than silently crashing with a generic 502.

### Issue 3: `EnableWorkerIndexing` flag causes inconsistent behavior

**Problem:** We set `AzureWebJobsFeatureFlags=EnableWorkerIndexing` per some documentation suggesting it's required for the v4 programming model. With this flag:
- Function triggers registered during deploy (shown in CLI output)
- But the worker process failed to initialize at runtime
- Application Insights showed: "Did not find any initialized language workers"
- Messages went to dead letter queue

Removing the flag allowed the function to work briefly, but adding it back (as suggested by other docs) broke it again.

**Result:** Contradictory behavior — the flag is documented as required for v4 but causes failures in practice on Linux Consumption.

**Suggestion:** Clarify in documentation whether `EnableWorkerIndexing` is required, optional, or harmful for the v4 Node.js programming model on Linux Consumption plans. If it's auto-detected, state that explicitly.

### Issue 4: Scale controller backs off after dead-lettered messages

**Problem:** After messages were dead-lettered due to the worker crash issues above, the consumption plan's scale controller appeared to back off aggressively. Even after:
- Fixing the deployment
- Purging the dead letter queue
- Stop/starting the function app
- Restarting the function app

The function would not pick up new messages for extended periods (5-10+ minutes), sometimes not at all. No Application Insights telemetry was produced, suggesting the host wasn't even spinning up an instance.

**Result:** Unreliable message processing. Function works once, then stops responding to new queue messages despite correct configuration.

**Suggestion:** Provide a way to reset the scale controller's backoff state. A simple "force scale" button in the portal or CLI command would save significant debugging time.

### Issue 5: No diagnostic logging when worker fails to start

**Problem:** Throughout all these issues, Application Insights showed zero traces, zero exceptions from the function app. The only way to diagnose problems was:
- Checking the HTTP response (502 vs 404 vs timeout)
- Checking Service Bus queue message counts
- Inferring the issue from the absence of telemetry

**Result:** Hours of trial-and-error debugging with no error messages to guide us.

**Suggestion:** The Azure Functions host should log startup failures, module load errors, and worker initialization errors to Application Insights before the worker process crashes. Even a single "Worker process failed to start: [error]" trace would have saved hours.

---

## What We Tried (Chronologically)

1. ✅ Initial deploy via `release.sh` — **worked** (functions registered, message consumed)
2. ❌ Redeployed with `func azure functionapp publish --javascript` — triggers not syncing
3. ❌ Added `EnableWorkerIndexing` — worker crash ("Did not find any initialized language workers")
4. ✅ Removed `EnableWorkerIndexing` — consumed one message, then stopped
5. ❌ Reverted to old function code — same trigger sync failure
6. ❌ Created `.funcignore` — trigger sync still failed
7. ❌ Pinned `@azure/functions` to 4.5.1 — same failure
8. ❌ Deleted and recreated function app — same failure
9. ❌ Recreated with Node 22 — same failure
10. ❌ Set plain values instead of Key Vault references — 404 (host starts, no functions)
11. ✅ Used `--build remote` — **functions registered** and message consumed
12. ❌ After restart, function stopped processing new messages — scale controller backoff
13. ❌ Purged dead letter queue, restarted — still no processing
14. ✅ Set plain values + remote build — function started but 502 on admin endpoint
15. ❌ Re-added `EnableWorkerIndexing` — no effect
16. ❌ Set `WEBSITE_RUN_FROM_PACKAGE=1` — no effect

**Resolution:** Moved plan generation logic into the Azure Container App as a direct API call, bypassing Azure Functions entirely.

---

## Impact

- ~6 hours of debugging time
- Architecture change: moved from async Service Bus + Azure Functions to synchronous in-process generation in Container App
- Loss of auto-retry semantics provided by Service Bus dead-letter queue
- Loss of independent scaling for plan generation workload
- Daily reminder timer trigger (`send-daily-reminders`) still depends on Azure Functions — remains a risk

---

## Reproduction

1. Create a Linux Consumption Function App (Node 20, Functions v4)
2. Deploy a TypeScript function using `@azure/functions` v4 programming model with:
- Service Bus trigger (`app.serviceBusQueue()`)
- Prisma ORM (`@prisma/client` with `linux-musl-openssl-3.0.x` target)
- `"main": "dist/index.js"` in package.json
3. Deploy from Windows using `func azure functionapp publish --javascript`
4. Observe: triggers may or may not sync. Worker may or may not start. Messages may or may not be consumed.

---

## Desired Outcome

1. Clear error logging when worker fails to start (not silent 502)
2. `func` CLI warns when `main` entry point is excluded by `.gitignore`
3. Documentation clarity on `EnableWorkerIndexing` for v4 model
4. Mechanism to reset scale controller backoff
5. Reliable cold start for Service Bus triggers on Consumption plan (< 60 seconds)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.