Azure Functions là dịch vụ serverless của Microsoft Azure, tương tự AWS Lambda. Bài này hướng dẫn xây dựng và deploy Azure Functions với NodeJS/TypeScript cho các tác vụ phổ biến: HTTP trigger, Timer trigger, và Queue trigger.
1. Cài đặt
npm install -g azure-functions-core-tools@4
npm install -g @azure/functions
Tạo project mới:
func init my-functions --typescript
cd my-functions
2. HTTP Trigger — REST API
func new --name HttpUsers --template "HTTP trigger"
// src/functions/HttpUsers.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';
export async function httpUsers(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
context.log(`HTTP function processed request for url "${request.url}"`);
const method = request.method;
if (method === 'GET') {
const id = request.query.get('id');
if (id) {
// Query database...
return { status: 200, jsonBody: { id, name: 'Nguyen Van A', email: 'a@example.com' } };
}
return { status: 200, jsonBody: { users: [] } };
}
if (method === 'POST') {
const body = await request.json() as { name: string; email: string };
// Create user...
return { status: 201, jsonBody: { id: 'new-id', ...body } };
}
return { status: 405, body: 'Method not allowed' };
}
app.http('HttpUsers', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: httpUsers,
});
3. Timer Trigger — Scheduled Job
// src/functions/DailyReport.ts
import { app, InvocationContext, Timer } from '@azure/functions';
export async function dailyReport(
timer: Timer,
context: InvocationContext,
): Promise<void> {
const now = new Date().toISOString();
context.log(`Daily report function ran at: ${now}`);
if (timer.isPastDue) {
context.log('Timer is running late!');
}
// Tạo báo cáo hàng ngày...
// await generateAndSendReport();
}
app.timer('DailyReport', {
// Chạy mỗi ngày lúc 8:00 AM (UTC+7 = 1:00 AM UTC)
schedule: '0 0 1 * * *',
handler: dailyReport,
});
4. Queue Trigger — Xử lý Azure Storage Queue
// src/functions/ProcessEmail.ts
import { app, InvocationContext, StorageQueueHandler } from '@azure/functions';
const processEmail: StorageQueueHandler = async (
queueItem: unknown,
context: InvocationContext,
): Promise<void> => {
context.log('Processing queue item:', queueItem);
const { to, subject, body } = queueItem as { to: string; subject: string; body: string };
// Gửi email...
context.log(`Email sent to ${to}`);
};
app.storageQueue('ProcessEmail', {
queueName: 'email-queue',
connection: 'AzureStorageConnection',
handler: processEmail,
});
5. Blob Trigger — Xử lý khi có file mới upload lên Azure Blob
// src/functions/ProcessImage.ts
import { app, InvocationContext, StorageBlobHandler } from '@azure/functions';
const processImage: StorageBlobHandler = async (
blob: unknown,
context: InvocationContext,
): Promise<void> => {
context.log('Blob trigger function processed blob:');
context.log('Name:', context.triggerMetadata?.name);
context.log('Size:', (blob as Buffer).length, 'bytes');
// Resize, watermark, analyze ảnh...
};
app.storageBlob('ProcessImage', {
path: 'uploads/{name}', // Trigger khi có file mới trong container "uploads"
connection: 'AzureStorageConnection',
handler: processImage,
});
6. Kết nối Database
import { MongoClient } from 'mongodb';
// Kết nối ngoài handler để reuse (tương tự Lambda)
let mongoClient: MongoClient | null = null;
async function getDb() {
if (!mongoClient) {
mongoClient = new MongoClient(process.env.MONGODB_URI!);
await mongoClient.connect();
}
return mongoClient.db('mydb');
}
export async function httpUsers(request: HttpRequest, context: InvocationContext) {
const db = await getDb();
const users = await db.collection('users').find().toArray();
return { jsonBody: users };
}
7. local.settings.json
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "node",
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"AzureStorageConnection": "DefaultEndpointsProtocol=http;...",
"MONGODB_URI": "mongodb://localhost:27017/mydb",
"NODE_ENV": "development"
}
}
8. Chạy local và Deploy
# Chạy local
func start
# Build TypeScript
npm run build
# Deploy lên Azure (cần Azure CLI đã login)
func azure functionapp publish my-function-app
Deploy qua GitHub Actions
- name: Deploy to Azure Functions
uses: Azure/functions-action@v1
with:
app-name: my-function-app
package: .
publish-profile: $
9. So sánh Azure Functions vs AWS Lambda
| Tiêu chí | Azure Functions | AWS Lambda |
|---|---|---|
| Free tier | 1M executions/tháng | 1M executions/tháng |
| Max timeout | 10 phút (Consumption) / 230 phút (Premium) | 15 phút |
| Cold start | Tương đương | Tương đương |
| Triggers | Nhiều (HTTP, Timer, Queue, Blob, Service Bus…) | Nhiều (API GW, SQS, S3, EventBridge…) |
| Tích hợp | Azure ecosystem | AWS ecosystem |
| Local dev | Azure Functions Core Tools | SAM CLI |
10. Kết luận
Azure Functions phù hợp khi:
- Hệ thống đang dùng Azure (Azure SQL, Cosmos DB, Blob Storage…)
- Cần tích hợp với Azure Service Bus, Event Grid
- Cần timer trigger phức tạp hoặc timeout dài hơn Lambda
Với NodeJS/TypeScript, DX của Azure Functions rất tốt — code giống NestJS controller, dễ học.