Thử lại các hàm không đồng bộ

Tài liệu này mô tả cách bạn có thể yêu cầu các hàm nền không đồng bộ (không phải HTTPS) để thử lại khi không thành công.

Ngữ nghĩa của việc thử lại

Cloud Functions đảm bảo việc thực thi hàm dựa trên sự kiện ít nhất một lần cho mỗi sự kiện do một nguồn sự kiện phát ra. Theo mặc định, nếu lệnh gọi hàm kết thúc kèm theo lỗi, thì hàm sẽ không được gọi lại và sự kiện sẽ bị loại bỏ. Khi bạn bật tính năng thử lại trên một hàm dựa trên sự kiện, Cloud Functions sẽ thực hiện lại một lệnh gọi hàm không thành công cho đến khi hàm đó hoàn tất thành công hoặc khi cửa sổ thử lại hết hạn.

Đối với các hàm thế hệ thứ 2, khoảng thời gian thử lại này sẽ hết hạn sau 24 giờ. Đối với các hàm thế hệ 1, hàm sẽ hết hạn sau 7 ngày. Cloud Functions dùng lại các hàm dựa trên sự kiện mới tạo bằng cách sử dụng chiến lược thời gian đợi luỹ thừa, với thời gian đợi tăng dần trong khoảng từ 10 đến 600 giây. Chính sách này được áp dụng cho các hàm mới trong lần đầu tiên bạn triển khai các hàm đó. Chính sách này không áp dụng cho các hàm hiện có được triển khai lần đầu trước khi những thay đổi được mô tả trong ghi chú phát hành này có hiệu lực, ngay cả khi bạn triển khai lại các hàm đó.

Khi bạn không bật tính năng thử lại cho một hàm (theo mặc định), hàm này sẽ luôn báo cáo rằng hàm được thực thi thành công và mã phản hồi 200 OK có thể xuất hiện trong nhật ký của hàm. Điều này xảy ra ngay cả khi hàm gặp lỗi. Để làm rõ thời điểm hàm của bạn gặp lỗi, hãy nhớ báo cáo lỗi một cách thích hợp.

Lý do không thể hoàn tất các chức năng dựa trên sự kiện

Trong một số ít trường hợp, một hàm có thể thoát sớm do lỗi nội bộ và theo mặc định, hàm này có thể được hoặc không được tự động thử lại.

Thông thường, một hàm dựa trên sự kiện có thể không hoàn tất thành công do các lỗi được tạo ra trong chính mã hàm đó. Điều này có thể xảy ra vì những lý do sau:

  • Hàm này chứa một lỗi và môi trường thời gian chạy gửi ra một ngoại lệ.
  • Hàm không thể đạt đến một điểm cuối dịch vụ hoặc hết thời gian chờ trong khi cố gắng thực hiện việc đó.
  • Hàm này chủ ý gửi một trường hợp ngoại lệ (ví dụ: khi một tham số không xác thực được).
  • Hàm Node.js trả về một lời hứa bị từ chối hoặc chuyển giá trị không phải là null cho một lệnh gọi lại.

Trong bất kỳ trường hợp nào ở trên, theo mặc định, hàm sẽ ngừng thực thi và sự kiện sẽ bị loại bỏ. Để thử lại hàm này khi xảy ra lỗi, bạn có thể thay đổi chính sách thử lại mặc định bằng cách đặt thuộc tính "thử lại khi không thành công". Điều này khiến sự kiện được thử lại nhiều lần cho đến khi hàm hoàn tất thành công hoặc hết thời gian chờ thử lại.

Bật hoặc tắt tính năng thử lại

Định cấu hình hoạt động thử lại trong Bảng điều khiển GCP

Nếu bạn đang tạo một hàm mới:

  1. Trên màn hình Create Function (Tạo hàm), hãy chọn Add kích hoạt (Thêm điều kiện kích hoạt) rồi chọn loại sự kiện sẽ đóng vai trò là điều kiện kích hoạt cho hàm của bạn.
  2. Trong ngăn Eventarc kích hoạt, hãy chọn hộp đánh dấu Thử lại khi không thành công để cho phép thử lại.

Nếu bạn đang cập nhật một hàm hiện có:

  1. Trên trang Tổng quan về hàm trên đám mây, hãy nhấp vào tên hàm bạn đang cập nhật để mở màn hình Chi tiết hàm, sau đó chọn Chỉnh sửa trên thanh trình đơn để hiển thị ngăn kích hoạt HTTPSEventarc.
  2. Trong ngăn điều kiện kích hoạt Eventarc, hãy nhấp vào biểu tượng chỉnh sửa để chỉnh sửa chế độ cài đặt của điều kiện kích hoạt.
  3. Trong ngăn điều kiện kích hoạt Eventarc, hãy chọn hoặc bỏ đánh dấu hộp kiểm Thử lại khi không thành công để bật hoặc tắt tính năng thử lại.

Định cấu hình các lần thử lại trong mã hàm

Với Cloud Functions dành cho Firebase, bạn có thể cho phép thử lại trong mã của một hàm. Để thực hiện việc này cho hàm nền như functions.foo.onBar(myHandler);, hãy sử dụng runWith và định cấu hình chính sách lỗi:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

Việc đặt true như hình sẽ định cấu hình một hàm để thử lại khi không thành công.

Các phương pháp hay nhất

Phần này mô tả các phương pháp hay nhất để sử dụng tính năng thử lại.

Dùng thử lại để xử lý các lỗi tạm thời

Vì hàm này được thử lại liên tục cho đến khi thực thi thành công, nên các lỗi vĩnh viễn như lỗi sẽ bị loại bỏ khỏi mã của bạn trong quá trình kiểm thử trước khi cho phép thử lại. Tốt nhất là bạn nên thử lại để xử lý các sự cố không liên tục/tạm thời có khả năng giải quyết cao khi thử lại, chẳng hạn như điểm cuối của dịch vụ không ổn định hoặc hết thời gian chờ.

Đặt điều kiện kết thúc để tránh vòng lặp thử lại vô hạn

Phương pháp hay nhất là bảo vệ hàm của bạn khỏi tình trạng lặp lại liên tục khi sử dụng lần thử lại. Bạn có thể thực hiện việc này bằng cách thêm một điều kiện kết thúc được xác định rõ ràng, trước khi hàm bắt đầu xử lý. Lưu ý rằng kỹ thuật này chỉ hoạt động nếu hàm của bạn bắt đầu thành công và có thể đánh giá điều kiện kết thúc.

Một phương pháp đơn giản nhưng hiệu quả là loại bỏ các sự kiện có dấu thời gian cũ hơn một thời gian nhất định. Điều này giúp tránh tình trạng thực thi quá nhiều khi lỗi liên tục hoặc kéo dài hơn dự kiến.

Ví dụ: đoạn mã này loại bỏ tất cả những sự kiện diễn ra lâu hơn 10 giây:

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

Sử dụng catch với Lời hứa

Nếu hàm của bạn đã cho phép thử lại, thì mọi lỗi chưa được xử lý sẽ kích hoạt hoạt động thử lại. Hãy đảm bảo rằng mã của bạn ghi lại mọi lỗi không nên dẫn đến việc thử lại.

Dưới đây là ví dụ về những việc bạn nên làm:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

Đặt các hàm dựa trên sự kiện có thể thử lại không thay đổi

Các hàm hướng sự kiện có thể được thử lại phải không thay đổi. Dưới đây là một số nguyên tắc chung để tạo giá trị đồng nhất cho một hàm như vậy:

  • Nhiều API bên ngoài (chẳng hạn như Stripe) cho phép bạn cung cấp khoá giá trị nhận dạng dưới dạng tham số. Nếu đang sử dụng một API như vậy, bạn nên sử dụng mã sự kiện làm khoá idempotency.
  • Tính năng bình thường hoạt động tốt với chế độ phân phối ít nhất một lần, vì tính năng này giúp bạn an toàn thử lại. Vì vậy, phương pháp chung hay nhất để viết mã đáng tin cậy là kết hợp khả năng không hoạt động với số lần thử lại.
  • Đảm bảo rằng mã của bạn không thay đổi giá trị nội bộ. Ví dụ:
    • Đảm bảo rằng đột biến có thể xảy ra nhiều lần mà không cần thay đổi kết quả.
    • Truy vấn trạng thái của cơ sở dữ liệu trong một giao dịch trước khi thay đổi trạng thái.
    • Đảm bảo rằng tất cả tác dụng phụ đều có giá trị riêng biệt.
  • Áp dụng yêu cầu kiểm tra giao dịch bên ngoài hàm, độc lập với mã. Ví dụ: hãy duy trì trạng thái ở đâu đó bản ghi rằng một mã sự kiện nhất định đã được xử lý.
  • Xử lý các lệnh gọi hàm trùng lặp ngoài băng tần. Ví dụ: có một quy trình dọn dẹp riêng biệt để dọn dẹp sau các lệnh gọi hàm trùng lặp.

Định cấu hình chính sách thử lại

Tuỳ thuộc vào nhu cầu của Chức năng đám mây, bạn có thể muốn định cấu hình trực tiếp chính sách thử lại. Điều này sẽ cho phép bạn thiết lập bất kỳ tổ hợp nào sau đây:

  • Rút ngắn khoảng thời gian thử lại từ 7 ngày xuống còn 10 phút.
  • Thay đổi thời gian đợi tối thiểu và tối đa cho chiến lược thử lại thời gian đợi luỹ thừa.
  • Thay đổi chiến lược thử lại để thử lại ngay lập tức.
  • Định cấu hình một chủ đề có chữ cái.
  • Đặt số lần thử phân phối tối đa và tối thiểu.

Cách định cấu hình chính sách thử lại:

  1. Viết một hàm HTTP.
  2. Sử dụng API Pub/Sub để tạo một gói thuê bao Pub/Sub, trong đó chỉ định URL của hàm làm mục tiêu.

Xem Tài liệu về Pub/Sub về cách xử lý lỗi để biết thêm thông tin về cách định cấu hình trực tiếp Pub/Sub.