Lambda Durable Functions: Hướng dẫn toàn diện cho AWS Developer

Lambda Durable Functions: Hướng dẫn toàn diện cho AWS Developer

avatar

Long Ngo

2026.01.28

Hướng dẫn chi tiết Lambda Durable Functions cho Junior và Middle AWS developers. Bài viết giải thích cơ chế Checkpoint/Replay, so sánh với Step Functions, kèm ví dụ thực tế và bài thực hành để bạn có thể bắt đầu ngay.

00. Kiến thức cần có trước khi đọc

Trước khi đọc bài này, bạn nên có kiến thức cơ bản về:

  • AWS Lambda: Biết cách tạo function, gọi (invoke), và cấu hình trigger
  • Async/Await: Hiểu cách viết code bất đồng bộ trong JavaScript/TypeScript hoặc Python
  • API Gateway (không bắt buộc): Biết cách tạo HTTP endpoint cho Lambda

Nếu bạn chưa quen với Lambda, hãy đọc bài Generate Thumbnail Images using S3 Event Notification and Lambda trước.


01. Giới thiệu

Tại AWS re-Invent 2025, AWS đã công bố Lambda Durable Functions - một tính năng mới cho phép Lambda chạy các workflow dài lên đến 1 năm, với khả năng tự động tiếp tục khi gặp lỗi.

"Developers wanna build like you're building monoliths, but you want to deploy microservices" — Eric Johnson, Principal Developer Advocate, AWS

Nói đơn giản: Lambda Durable cho phép bạn viết code tuần tự, dễ đọc như ứng dụng thông thường, nhưng bên dưới nó tự động xử lý các vấn đề phức tạp của hệ thống phân tán (distributed systems).

Giải thích thuật ngữ:

  • Durable (Bền vững): Không bị mất trạng thái khi có lỗi
  • Checkpoint: Điểm lưu trạng thái - giống như "save game" trong game
  • Replay: Chạy lại code từ đầu, nhưng bỏ qua các bước đã hoàn thành
  • Orchestration: Điều phối nhiều service làm việc cùng nhau theo một luồng xử lý

02. Tại sao cần Lambda Durable?

2.1 Vấn đề với Lambda thông thường

Hãy tưởng tượng bạn đang xây dựng hệ thống xử lý đơn hàng e-commerce:

// Lambda thông thường - CÓ VẤN ĐỀ!
export const handler = async (event) => {
  // Bước 1: Kiểm tra đơn hàng (2 giây)
  const order = await validateOrder(event.orderId);

  // Bước 2: Trừ tiền khách hàng (3 giây)
  const payment = await chargePayment(order.amount);

  // Bước 3: Giảm tồn kho (2 giây)
  await reduceInventory(order.items);

  // Bước 4: Gửi email xác nhận (1 giây)
  await sendConfirmationEmail(order.email);

  // Bước 5: Đợi shipper xác nhận (có thể 2-3 ngày!)
  await waitForShipperConfirmation(order.id);  // ❌ QUÁ THỜI GIAN CHO PHÉP!

  return { status: 'completed' };
};

Các vấn đề:

Vấn đềMô tảHậu quả
Giới hạn 15 phútLambda chỉ chạy tối đa 15 phútKhông thể chờ shipper xác nhận
Không có checkpointNếu reduceInventory lỗi, phải chạy lại từ đầuKhách hàng bị trừ tiền 2 lần!
Phải tự xử lý retryPhải tự viết code thử lại khi lỗiCode phức tạp, khó bảo trì

2.2 Lambda Durable giải quyết như thế nào?

// Lambda Durable - GIẢI QUYẾT TẤT CẢ!
import { withDurableExecution, DurableContext } from '@aws-lambda-powertools/durable';

export const handler = withDurableExecution(async (ctx: DurableContext, event) => {
  // Bước 1: Kiểm tra - được LƯU TRẠNG THÁI sau khi xong
  const order = await ctx.step('validate', () => validateOrder(event.orderId));

  // Bước 2: Trừ tiền - được LƯU TRẠNG THÁI sau khi xong
  const payment = await ctx.step('charge', () => chargePayment(order.amount));

  // Bước 3: Giảm tồn kho - được LƯU TRẠNG THÁI sau khi xong
  await ctx.step('reduce-inventory', () => reduceInventory(order.items));

  // Bước 4: Gửi email - được LƯU TRẠNG THÁI sau khi xong
  await ctx.step('send-email', () => sendConfirmationEmail(order.email));

  // Bước 5: Đợi shipper - CÓ THỂ ĐỢI HÀNG NGÀY!
  await ctx.waitForCallback('shipper-confirm', {
    callbackId: order.id,
    timeout: '7d'  // Đợi tối đa 7 ngày
  });

  return { status: 'completed' };
});

Kết quả:

  • Có thể chạy lên đến 1 năm
  • Nếu lỗi ở bước 3, tự động tiếp tục từ bước 3 (không trừ tiền lại)
  • Code vẫn đơn giản, tuần tự, dễ đọc

03. Cơ chế Checkpoint và Replay - Trái tim của Durable

Đây là phần quan trọng nhất cần hiểu. Hãy xem sơ đồ AWS cung cấp:

Để dễ hiểu hơn mình xem như bên dưới:

Điểm quan trọng cần nhớ:

  1. Code luôn chạy từ đầu function mỗi lần chạy lại
  2. Các bước đã lưu trạng thái sẽ bỏ qua việc thực thi và trả về kết quả đã lưu
  3. Vì vậy, không bao giờ trừ tiền 2 lần dù code chạy từ đầu

3.1 Ví dụ minh họa chi tiết

export const handler = withDurableExecution(async (ctx, event) => {
  console.log('Handler bắt đầu chạy');  // In ra MỖI LẦN chạy lại

  // Lần 1: Thực thi và lưu kết quả
  // Lần 2+: Bỏ qua và trả về kết quả đã lưu
  const step1Result = await ctx.step('step-1', async () => {
    console.log('Step 1 đang thực thi');  // CHỈ in lần đầu
    return 'result-from-step-1';
  });

  console.log(`Step 1 result: ${step1Result}`);  // In MỖI LẦN, nhưng kết quả giống nhau

  // Tương tự cho các step khác...
});

Kết quả lần chạy đầu:

Handler bắt đầu chạy
Step 1 đang thực thi
Step 1 result: result-from-step-1

Kết quả khi chạy lại (step 1 đã lưu trạng thái):

Handler bắt đầu chạy
Step 1 result: result-from-step-1

(Không có "Step 1 đang thực thi" vì nó được bỏ qua!)

04. Các thành phần cơ bản

4.1 ctx.step() - Đơn vị công việc được lưu trạng thái

// Cú pháp cơ bản
const result = await ctx.step('tên-step-duy-nhất', async () => {
  // Code xử lý ở đây
  return 'kết quả';
});

// Ví dụ thực tế
const user = await ctx.step('get-user', async () => {
  const response = await fetch(`https://api.example.com/users/${userId}`);
  return response.json();
});

Quy tắc đặt tên step:

  • Phải duy nhất trong function
  • Nên mô tả rõ step làm gì: 'validate-order', 'charge-payment', 'send-email'

4.2 ctx.wait() - Chờ đợi thông minh

Lambda Durable hỗ trợ 3 kiểu chờ:

4.2.1 Chờ theo thời gian (Timer Wait)

// Chờ 24 giờ rồi gửi email nhắc nhở
await ctx.step('create-order', () => createOrder(event));

await ctx.wait('wait-24h', { duration: '24h' });  // Lambda "ngủ" 24 giờ

await ctx.step('send-reminder', () => sendReminderEmail(event.email));

Trường hợp sử dụng: Gửi nhắc nhở sau X ngày, thử lại sau một khoảng thời gian

4.2.2 Chờ sự kiện bên ngoài (Callback Wait)

// Chờ quản lý phê duyệt
const approval = await ctx.waitForCallback('manager-approval', {
  callbackId: `request-${requestId}`,
  timeout: '7d'
});

if (approval.status === 'approved') {
  await ctx.step('process', () => processRequest(requestId));
} else {
  await ctx.step('reject', () => rejectRequest(requestId));
}

Kích hoạt callback từ bên ngoài:

# Quản lý click nút Phê duyệt → gọi API này
aws lambda invoke-durable-callback \
  --function-name MyFunction \
  --callback-id "request-12345" \
  --payload '{"status": "approved", "approver": "manager@company.com"}'

Trường hợp sử dụng: Phê duyệt từ người dùng, webhook thanh toán, tích hợp bên thứ ba

4.2.3 Chờ điều kiện thỏa mãn (Condition Wait)

// Kiểm tra định kỳ đến khi thanh toán được xác nhận
await ctx.waitForCondition('payment-confirmed', async () => {
  const status = await checkPaymentStatus(paymentId);
  return status === 'SUCCESS';  // true → dừng chờ
}, {
  interval: '30s',   // Kiểm tra mỗi 30 giây
  timeout: '2h'      // Hết hạn sau 2 giờ
});

Trường hợp sử dụng: Đợi hệ thống bên ngoài sẵn sàng, kiểm tra trạng thái định kỳ

4.3 ctx.parallel() - Thực thi song song

// Chạy 3 lệnh gọi API cùng lúc thay vì tuần tự
const [inventory, pricing, shipping] = await ctx.parallel([
  ctx.step('check-inventory', () => checkInventory(productId)),
  ctx.step('get-pricing', () => getPricing(productId)),
  ctx.step('calculate-shipping', () => calculateShipping(address))
]);

// Tổng thời gian = thời gian của lệnh lâu nhất (thay vì tổng 3 lệnh)

05. Saga Pattern - Xử lý lỗi trong hệ thống phân tán

5.1 Vấn đề: Giao dịch phân tán (Distributed Transaction)

Hãy tưởng tượng bạn đang xây dựng hệ thống đặt tour du lịch:

Đặt Tour Đà Nẵng 3N2Đ:
1. Đặt vé máy bay VN Airlines: 5,000,000 VNĐ
2. Đặt khách sạn Hilton: 3,000,000 VNĐ
3. Đặt xe đưa đón sân bay: 500,000 VNĐ
```saga-pattern-tour-booking.drawio

**Vấn đề**: Nếu bước 3 (đặt xe) lỗi, bạn cần:
- Hủy vé máy bay (bước 1) → hoàn tiền
- Hủy khách sạn (bước 2) → hoàn tiền

Đây gọi là **compensation** (bù đắp/hoàn tác).

### 5.2 Saga Pattern với Lambda Durable

```typescript
export const handler = withDurableExecution(async (ctx: DurableContext, event) => {
  const { customerId, tourId, flightDate, hotelDate } = event;

  // Bước 1: Đặt vé máy bay
  // Nếu các bước sau lỗi → gọi cancelFlight để hoàn vé
  const flight = await ctx.step('book-flight',
    async () => {
      const booking = await flightAPI.book({
        customerId,
        date: flightDate,
        route: 'SGN-DAD'
      });
      return booking;
    },
    {
      compensation: async () => {
        await flightAPI.cancel(flight.bookingId);
        console.log('Đã hoàn vé máy bay');
      }
    }
  );

  // Bước 2: Đặt khách sạn
  // Nếu các bước sau lỗi → gọi cancelHotel để hủy phòng
  const hotel = await ctx.step('book-hotel',
    async () => {
      const booking = await hotelAPI.book({
        customerId,
        date: hotelDate,
        hotel: 'Hilton Da Nang'
      });
      return booking;
    },
    {
      compensation: async () => {
        await hotelAPI.cancel(hotel.bookingId);
        console.log('Đã hủy đặt phòng khách sạn');
      }
    }
  );

  // Bước 3: Đặt xe đưa đón
  // Nếu lỗi ở đây → TỰ ĐỘNG gọi compensation của bước 2, rồi bước 1
  const car = await ctx.step('book-car', async () => {
    const booking = await carAPI.book({
      customerId,
      pickupTime: flightDate,
      location: 'Da Nang Airport'
    });
    return booking;
  });

  // Nếu tất cả thành công
  return {
    status: 'success',
    bookings: { flight, hotel, car }
  };
});

Luồng xử lý khi bước 3 lỗi:

06. So sánh Lambda Durable với Step Functions

Tiêu chíLambda DurableStep Functions
Cách viếtCode TypeScript/PythonJSON (Amazon States Language)
Độ khó họcDễ (quen thuộc với lập trình viên)Trung bình (cần học ngôn ngữ mới)
Gỡ lỗiConsole.log, breakpointsGiao diện lịch sử thực thi
Kiểm thử đơn vịJest/pytest bình thườngCần mock phức tạp
Trực quan hóaKhông có giao diện sơ đồCó giao diện workflow đẹp
Tích hợp AWSCần viết code trong stepHơn 220 tích hợp trực tiếp
Chi phí$8/triệu thao tác$25/triệu chuyển đổi trạng thái

6.1 Khi nào nên dùng Lambda Durable?

Dùng Lambda Durable khi:

  • Team của bạn thích viết code hơn kéo thả giao diện
  • Logic phức tạp với nhiều if/else, vòng lặp
  • Cần kiểm thử đơn vị dễ dàng
  • Muốn tiết kiệm chi phí (rẻ hơn ~68%)

Dùng Step Functions khi:

  • Cần sơ đồ workflow trực quan cho BA/stakeholder xem
  • Nhiều tích hợp AWS service (S3, DynamoDB, SQS...)
  • Team có người không phải lập trình viên
  • Cần giao diện lịch sử thực thi chi tiết

6.2 Có thể kết hợp cả hai

Step Functions (Điều phối cấp cao)
    ├── Lambda Durable (Logic nghiệp vụ phức tạp)
    │       └── Xử lý đơn hàng với Saga pattern
    ├── Lambda đơn giản (Tác vụ nhanh)
    │       └── Gửi thông báo
    └── Tích hợp AWS trực tiếp
            └── Ghi vào DynamoDB

07. Bài thực hành: Hello Durable

Hãy tạo một Lambda Durable function đơn giản để làm quen.

7.1 Bước 1: Tạo dự án

mkdir hello-durable && cd hello-durable
npm init -y
npm install @aws-lambda-powertools/durable typescript @types/node

7.2 Bước 2: Viết code

src/index.ts:

import { withDurableExecution, DurableContext } from '@aws-lambda-powertools/durable';

interface OrderEvent {
  orderId: string;
  customerEmail: string;
  amount: number;
}

export const handler = withDurableExecution(async (
  ctx: DurableContext,
  event: OrderEvent
) => {
  console.log(`Đang xử lý đơn hàng: ${event.orderId}`);

  // Bước 1: Kiểm tra đơn hàng
  const isValid = await ctx.step('validate-order', async () => {
    console.log('Đang kiểm tra đơn hàng...');
    // Giả lập kiểm tra
    await sleep(1000);
    return event.amount > 0;
  });

  if (!isValid) {
    return { status: 'failed', reason: 'Số tiền không hợp lệ' };
  }

  // Bước 2: Xử lý thanh toán
  const paymentId = await ctx.step('process-payment', async () => {
    console.log('Đang xử lý thanh toán...');
    await sleep(2000);
    return `PAY-${Date.now()}`;
  });

  // Bước 3: Gửi xác nhận
  await ctx.step('send-confirmation', async () => {
    console.log(`Đang gửi email đến ${event.customerEmail}`);
    await sleep(500);
  });

  return {
    status: 'completed',
    orderId: event.orderId,
    paymentId: paymentId
  };
});

const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

7.3 Bước 3: Cấu hình SAM

template.yaml:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  HelloDurableFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: hello-durable
      Handler: dist/index.handler
      Runtime: nodejs22.x
      Timeout: 900
      MemorySize: 256
      DurableExecution:
        Enabled: true
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - lambda:CheckpointDurableExecution
                - lambda:GetDurableExecutionState
              Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:hello-durable'

7.4 Bước 4: Triển khai và kiểm tra

# Build
npm run build

# Triển khai
sam deploy --guided

# Kiểm tra
aws lambda invoke \
  --function-name hello-durable \
  --payload '{"orderId":"ORD-001","customerEmail":"test@example.com","amount":100}' \
  response.json

cat response.json

08. Nhược điểm cần chú ý

Lambda Durable không phải "viên đạn bạc"!

Mặc dù Lambda Durable mang lại nhiều lợi ích, nhưng bạn cần hiểu rõ các nhược điểm để đưa ra quyết định kiến trúc phù hợp. Đừng dùng Lambda Durable cho mọi trường hợp - hãy cân nhắc kỹ trước khi áp dụng.

8.1 Code không xác định kết quả (Non-deterministic) bên ngoài step

"Non-deterministic code" là gì?

Trong lập trình, có 2 loại code:

LoạiĐặc điểmVí dụ
Deterministic (Xác định)Cùng input → luôn cho cùng output2 + 2 luôn = 4
Non-deterministic (Không xác định)Cùng input → mỗi lần cho output khácMath.random() mỗi lần khác

Các hàm Non-deterministic phổ biến:

  • Math.random() → số ngẫu nhiên khác nhau mỗi lần
  • Date.now(), new Date() → thời gian khác nhau mỗi lần
  • crypto.randomUUID() → UUID khác nhau mỗi lần
  • Gọi API bên ngoài → response có thể khác nhau

Tại sao đây là vấn đề với Lambda Durable?

Hãy xem ví dụ cụ thể:

// ❌ SAI - UUID nằm NGOÀI step
const orderId = crypto.randomUUID();  // Dòng này chạy MỖI LẦN replay!
await ctx.step('create-order', () => createOrder(orderId));
await ctx.step('send-email', () => sendEmail(orderId));  // orderId có thể KHÁC!

Vấn đề xảy ra như sau:

Lần chạy 1:
─────────────────────────────────────────────────────────
orderId = crypto.randomUUID()"abc-123"
create-order với "abc-123"        → ✅ Thành công, lưu checkpoint
send-email với "abc-123"          → ❌ LI! (mất mạng)

Lần chạy 2 (Replay):
─────────────────────────────────────────────────────────
orderId = crypto.randomUUID()"xyz-789" (KHÁC vì random lại!)
create-order với "xyz-789"        → ⏩ Bqua (đã có checkpoint)
                                     NHƯNG checkpoint lưu cho "abc-123"!
send-email với "xyz-789"          → ✅ Gửi email cho order SAI!

KT QU: Order "abc-123" được tạo nhưng email gửi cho "xyz-789" (không tồn tại)

Cách sửa đúng:

// ✅ ĐÚNG - Bọc trong step để lưu kết quả
const orderId = await ctx.step('generate-id', () => crypto.randomUUID());
// Lần 1: thực thi → "abc-123" (LƯU vào checkpoint)
// Lần 2: bỏ qua → trả về "abc-123" từ checkpoint (GIỐNG lần 1!)

await ctx.step('create-order', () => createOrder(orderId));  // Luôn dùng "abc-123"
await ctx.step('send-email', () => sendEmail(orderId));      // Luôn dùng "abc-123"

Quy tắc vàng: Mọi thứ ngẫu nhiên, thời gian, UUID phải nằm trong ctx.step() để được lưu lại.

8.2 Thay đổi biến bên ngoài step - Lỗi âm thầm

"Thay đổi biến bên ngoài step" (Closure Mutation) là gì?

Khi bạn khai báo một biến bên ngoài ctx.step(), sau đó thay đổi giá trị của nó bên trong step - đây gọi là "mutation" (thay đổi).

let counter = 0;           // Biến khai báo BÊN NGOÀI step
await ctx.step('increment', () => {
  counter = counter + 1;   // Thay đổi biến BÊN TRONG step → Mutation!
});

Vấn đề: Lambda Durable chỉ lưu kết quả trả về từ step (qua return), KHÔNG lưu các biến bên ngoài bị thay đổi.

Xem ví dụ cụ thể để hiểu vấn đề:

// ❌ SAI - Thay đổi biến `total` bên ngoài step
let total = 0;  // Khai báo bên ngoài

for (const item of items) {  // items = [{id: 1, price: 100}, {id: 2, price: 200}]
  await ctx.step(`process-${item.id}`, async () => {
    total += item.price;  // Thay đổi biến bên ngoài → KHÔNG được lưu!
  });
}

console.log(total);  // Mong đợi: 300, nhưng kết quả có thể SAI!

Vấn đề xảy ra như sau:

Lần chạy 1:
─────────────────────────────────────────────────────────
total = 0                          (khởi tạo)
process-1: total += 100 → total = 100   ✅ checkpoint
process-2: total += 200 → total = 300LI! (mất mạng)

Lần chạy 2 (Replay):
─────────────────────────────────────────────────────────
total = 0                          (khởi tạo LI từ đầu!)
process-1:Bqua (có checkpoint)
           NHƯNG total vẫn = 0 (vì mutation không được lưu!)
process-2: total += 200 → total = 200   ✅ checkpoint

KT QU: total = 200 (SAI! đáng lẽ phải là 300)

Cách sửa đúng - Dùng return để lưu kết quả:

// ✅ ĐÚNG - Trả về kết quả từ step thay vì thay đổi biến ngoài
const prices = [];

for (const item of items) {
  const price = await ctx.step(`process-${item.id}`, async () => {
    return item.price;  // RETURN → được lưu vào checkpoint!
  });
  prices.push(price);  // prices được xây dựng từ kết quả đã lưu
}

const total = prices.reduce((a, b) => a + b, 0);
console.log(total);  // Luôn đúng: 300

Tại sao cách này đúng?

Lần chạy 2 (Replay):
─────────────────────────────────────────────────────────
prices = []
process-1:Bỏ qua → return 100 từ checkpoint → prices = [100]
process-2:Thực thi → return 200 → prices = [100, 200]
total = 100 + 200 = 300  ✅ ĐÚNG!

Quy tắc: Không bao giờ thay đổi biến bên ngoài step. Luôn dùng return để trả về kết quả.

8.3 Phải dùng ARN đầy đủ phiên bản (Qualified ARN)

"Qualified ARN" là gì?

ARN (Amazon Resource Name) là định danh duy nhất cho mỗi tài nguyên AWS. Với Lambda, có 2 loại ARN:

LoạiVí dụĐặc điểm
Unqualified (Không đủ)arn:aws:lambda:...:function:MyFuncKhông có version/alias
Qualified (Đầy đủ)arn:aws:lambda:...:function:MyFunc:$LATESTCó version hoặc alias ở cuối

Tại sao Lambda Durable BẮT BUỘC phải dùng Qualified ARN?

Để hiểu, hãy xem cơ chế hoạt động của Replay:

TÌNH HUNG: Bạn deploy code mới GIA LÚC execution đang chạy

Ngày 1 - 9:00 AM: Execution bắt đầu với Code v1
─────────────────────────────────────────────────────────
Code v1:
  step('validate', () => validateOrder(order))     ✅ checkpoint
  step('charge', () => chargePayment(amount))LI!

Ngày 1 - 10:00 AM: Bạn deploy Code v2 (thay đổi logic)
─────────────────────────────────────────────────────────
Code v2:
  step('validate', () => validateOrderV2(order))   // Logic KHÁC!
  step('check-fraud', () => checkFraud(order))     // Step MỚI!
  step('charge', () => chargePaymentV2(amount))    // Logic KHÁC!

Ngày 1 - 10:05 AM: Lambda Durable tự động Replay
─────────────────────────────────────────────────────────

Nếu dùng Unqualified ARN (KHÔNG có version):

Replay chạy Code v2 (phiên bản MI NHT):
  step('validate'):Bỏ qua, trả về checkpoint
                    NHƯNG checkpoint lưu kết quả của validateOrder()
                    còn code mới là validateOrderV2()KHÔNG KHP!
  step('check-fraud'): 🤯 Step này KHÔNG CÓ checkpoint!
                       Vì code v1 không có step này!
  step('charge'): Logic chargePaymentV2() khác chargePayment()!

KT QU: Execution bị lỗi hoặc cho kết quả sai!

Nếu dùng Qualified ARN (CÓ version):

❌ arn:aws:lambda:us-east-1:123456789:function:MyFunction
✅ arn:aws:lambda:us-east-1:123456789:function:MyFunction:7
                                                    Version 7 (Code v1)
Replay vẫn chạy Code v1 (version 7):
  step('validate'):Bỏ qua, trả về checkpoint    ✅ Khớp!
  step('charge'): Chạy chargePayment() giống lần đầu ✅ Đúng logic!

KT QU: Execution hoàn thành đúng như mong đợi!

Các loại Qualified ARN hợp lệ:

✅ arn:aws:lambda:us-east-1:123456789:function:MyFunction:$LATEST
Dùng phiên bản mới nhất TI THI ĐIM bắt đầu execution

✅ arn:aws:lambda:us-east-1:123456789:function:MyFunction:7
Dùng chính xác phiên bản số 7

✅ arn:aws:lambda:us-east-1:123456789:function:MyFunction:prod
Dùng alias "prod" (alias trỏ đến một version cụ thể)

Quy tắc: Luôn publish version hoặc tạo alias khi deploy Lambda Durable. Không dùng ARN không có version.

8.4 Gỡ lỗi phức tạp hơn

Vì code chạy lại nhiều lần với các step được bỏ qua, việc debug có thể khó hiểu:

  • Log có thể không xuất hiện như mong đợi
  • Breakpoint có thể không dừng ở nơi bạn nghĩ
  • Cần hiểu rõ cơ chế replay để debug hiệu quả

8.5 Phụ thuộc vào AWS (Vendor Lock-in)

Lambda Durable là tính năng chỉ có trên AWS. Nếu bạn muốn chuyển sang cloud khác, sẽ cần viết lại toàn bộ logic orchestration.

09. Chi phí - Ước tính thực tế

Công thức:

Chi phí = (Số thao tác / 1,000,000) × $8 + Chi phí tính toán Lambda

Ví dụ thực tế:

Quy môĐơn hàng/ngàyBước/đơnThao tác/thángChi phí/tháng
Startup nhỏ100515,000~$0.12
Doanh nghiệp vừa1,0005150,000~$1.20
Doanh nghiệp lớn10,00051,500,000~$12.00
Lưu lượng cao100,000515,000,000~$120.00

So sánh với Step Functions:

  • Step Functions: 25/triuDoanhnghipln:25/triệu → Doanh nghiệp lớn: 37.50/tháng
  • Lambda Durable: 8/triuDoanhnghipln:8/triệu → Doanh nghiệp lớn: 12.00/tháng
  • Tiết kiệm ~68%

10. Sơ đồ quyết định: Chọn công nghệ nào?

Dựa vào yêu cầu của bạn, hãy theo sơ đồ sau để chọn công nghệ phù hợp:

10.1 Bảng tổng hợp quyết định

Yêu cầuLambdaLambda DurableStep FunctionsEC2/ECS
Tác vụ đơn giản, nhanh✅ Tốt nhất⚠️ Quá mức cần⚠️ Quá mức cần
Workflow nhiều bước, < 15 phút⚠️ Tự code✅ Tốt✅ Tốt
Workflow dài > 15 phút✅ Tốt nhất✅ Tốt⚠️ Phức tạp
Cần visual diagram cho BA✅ Tốt nhất
Logic phức tạp (if/else, loop)⚠️ Tự code✅ Tốt nhất⚠️ ASL khó⚠️
Saga pattern (rollback)✅ Native⚠️ Tự code⚠️ Tự code
Chờ human approval✅ Callback✅ Task Token⚠️ Tự code
Chạy 24/7 (web server)✅ Tốt nhất
Chi phí thấp nhất⚠️ Đắt hơn❌ Đắt nhất

10.2 Ví dụ thực tế

Trường hợpChọnLý do
API xử lý ảnh thumbnailLambdaĐơn giản, nhanh, event-driven
Xử lý đơn hàng e-commerceLambda DurableNhiều bước, cần Saga rollback
ETL pipeline chạy 2 tiếngLambda DurableDài hơn 15 phút, code-centric
Approval workflow cho HRStep FunctionsBA cần xem visual diagram
Web API backendECS/EC2Chạy liên tục, stateful
ML training jobECS/EC2Cần GPU, chạy lâu

11. Kết luận

Lambda Durable Functions là công cụ mới trong hệ sinh thái AWS Serverless, giúp xây dựng workflow dài hạn với code đơn giản. Tuy nhiên, nó không phải giải pháp cho mọi trường hợp - hãy dùng sơ đồ quyết định ở trên để chọn công nghệ phù hợp với yêu cầu cụ thể của bạn.

12. Tài liệu tham khảo