Azure Functions Serverless
Azure Functions is a serverless compute service that runs event-driven code without managing infrastructure. Functions scale automatically from zero to thousands of instances and you pay only for execution time and resources consumed. It integrates natively with Azure Storage, Service Bus, Event Hubs, Cosmos DB, and hundreds of other services.
How Functions Work
A function app consists of:
- Trigger: Event that invokes the function (HTTP, queue message, timer, blob upload)
- Bindings: Declarative connections to input/output data sources without boilerplate SDK code
- Host: Runtime that manages scaling, concurrency, and health
The Flex Consumption plan (2024+) offers faster cold starts and optional always-ready instances while keeping serverless billing.
Hosting Plans
| Plan | Scaling | Cold Start | VNet | Use Case |
|---|---|---|---|---|
| Consumption | Auto, pay per execution | Seconds | No | Most event-driven workloads |
| Flex Consumption | Auto, per-second billing | Faster | Optional | Production serverless |
| Premium | Pre-warmed instances | Minimal | Yes | Low-latency, long-running |
| Dedicated (App Service) | Manual/auto on ASP | None | Yes | Predictable workloads |
| Container Apps | KEDA-based | Low | Yes | Containerized functions |
Create an HTTP Trigger Function
# Install Core Tools
brew tap azure/functions
brew install azure-functions-core-tools@4
# Create project (Node.js v4 programming model)
func init MyFunctionApp --worker-runtime node --model V4
cd MyFunctionApp
func new --name HttpHello --template "HTTP trigger"
# Local run with storage emulator
func start
Example function (src/functions/HttpHello.js):
const { app } = require('@azure/functions');
app.http('HttpHello', {
methods: ['GET', 'POST'],
authLevel: 'function',
handler: async (request, context) => {
const name = request.query.get('name') || 'World';
context.log(`Processing request for: ${name}`);
return { status: 200, jsonBody: { message: `Hello, ${name}!` } };
}
});
Deploy to Azure
# Create storage account (required for Functions runtime state)
az storage account create \
--name stfuncprod001 \
--resource-group rg-webapp-prod \
--location eastus \
--sku Standard_LRS
# Create Function App on Consumption plan
az functionapp create \
--resource-group rg-webapp-prod \
--consumption-plan-location eastus \
--runtime node \
--runtime-version 20 \
--functions-version 4 \
--name func-webapp-prod \
--storage-account stfuncprod001 \
--os-type Linux
# Enable Application Insights
az monitor app-insights component create \
--app ai-func-prod \
--location eastus \
--resource-group rg-webapp-prod \
--application-type web \
--kind web
az functionapp config appsettings set \
--name func-webapp-prod \
--resource-group rg-webapp-prod \
--settings APPLICATIONINSIGHTS_CONNECTION_STRING="<connection-string>"
func azure functionapp publish func-webapp-prod
Common Triggers and Bindings
| Trigger | Binding Output | Use Case |
|---|---|---|
| HTTP | HTTP response | REST APIs, webhooks |
| Timer | — | Scheduled jobs (NCRONTAB syntax) |
| Blob | Blob output | Process uploaded files |
| Queue Storage | Queue output | Decouple with message queues |
| Service Bus | Service Bus output | Enterprise messaging |
| Event Hub | Event Hub output | Stream processing |
| Cosmos DB | Cosmos DB output | React to database changes |
Queue trigger example (function.json v1 style for reference):
{
"bindings": [
{
"name": "msg",
"type": "serviceBusTrigger",
"direction": "in",
"queueName": "orders",
"connection": "ServiceBusConnection"
}
]
}
Durable Functions
For workflows with state, retries, and orchestration across multiple functions:
const df = require('durable-functions');
df.app.orchestration('orderOrchestrator', function* (context) {
const order = context.df.getInput();
const inventory = yield context.df.callActivity('checkInventory', order);
if (!inventory.available) {
yield context.df.callActivity('notifyBackorder', order);
return { status: 'backordered' };
}
yield context.df.callActivity('processPayment', order);
yield context.df.callActivity('shipOrder', order);
return { status: 'shipped' };
});
Durable Functions persist orchestration state in Azure Storage or Netherite (Premium plan) — ideal for long-running approval workflows and fan-out/fan-in patterns.
Real-World Scenario: Image Processing Pipeline
| Component | Configuration |
|---|---|
| Trigger | Blob upload to uploads/ container |
| Processing | Resize, watermark, generate thumbnails |
| Output | Write to processed/ container; queue notification |
| Plan | Premium (VNet access to private storage) |
| Scaling | Max 200 concurrent instances; batch size 16 |
| Monitoring | App Insights dependency tracking; alert on failure rate > 1% |
Functions vs Alternatives
| Feature | Azure Functions | Logic Apps | Container Apps |
|---|---|---|---|
| Code | Full code (multi-language) | Low-code workflows | Container images |
| Complexity | Simple to moderate | Integration-focused | Microservices |
| Pricing | Per execution | Per action | Per vCPU-second |
| Stateful workflows | Durable Functions | Built-in | External store |
| Best for | Event-driven code | B2B integrations | Long-running services |
Common Mistakes
- Secrets in app settings as plaintext — use Key Vault references
- No dead-letter handling — poison messages loop forever on queue triggers
- Monolithic function apps — split by domain for independent scaling
- Ignoring timeout limits — Consumption max 5 min (configurable to 10); Premium up to unlimited
- Missing idempotency — retries cause duplicate processing without deduplication
- Cold start in latency-sensitive APIs — use Premium or Flex Consumption with always-ready
Troubleshooting
| Issue | Diagnosis | Fix |
|---|---|---|
| Function not triggering | Wrong connection string or trigger config | Verify app settings; check Storage queue/blob exists |
| 401 on HTTP trigger | Missing or wrong function key | Pass ?code=<key> or set authLevel: anonymous for public APIs |
| Timeout errors | Processing exceeds limit | Move to Premium plan; optimize code; use Durable Functions |
| High memory usage | Large payloads loaded entirely | Stream blob data; process in chunks |
| Deployment succeeds but 404 | Wrong runtime stack | Match --runtime and --functions-version to project |
# Stream live logs
func azure functionapp logstream func-webapp-prod
# List function keys
az functionapp function keys list \
--name func-webapp-prod \
--resource-group rg-webapp-prod \
--function-name HttpHello
Best Practices
- Keep functions small and focused — one responsibility per function
- Use Managed Identity instead of connection strings where supported
- Set retry policies and dead-letter queues for queue/Service Bus triggers
- Configure max concurrent requests to protect downstream dependencies
- Monitor with Application Insights — track duration, failures, dependencies
- Use deployment slots on Premium/Dedicated plans for zero-downtime releases
- Store configuration in App Configuration for feature flags and settings
Next: Azure Monitor.