Nâng cấp các hàm Node.js thế hệ 1 lên thế hệ 2

Các ứng dụng sử dụng hàm thế hệ thứ nhất nên cân nhắc việc di chuyển sang thế hệ thứ hai theo hướng dẫn trong tài liệu này. Các hàm thế hệ thứ 2 sử dụng Cloud Run để mang lại hiệu suất cao hơn, cấu hình tốt hơn, khả năng giám sát tốt hơn và nhiều lợi ích khác.

Các ví dụ trên trang này giả định rằng bạn đang sử dụng JavaScript với các mô-đun CommonJS (nhập kiểu require), nhưng các nguyên tắc tương tự cũng áp dụng cho JavaScript với ESM (nhập kiểu import … from) và TypeScript.

Quy trình di chuyển

Các hàm thế hệ thứ nhất và thế hệ thứ hai có thể cùng tồn tại trong cùng một tệp. Điều này giúp bạn dễ dàng di chuyển từng phần khi đã sẵn sàng. Bạn nên di chuyển từng hàm một, thực hiện kiểm thử và xác minh trước khi tiếp tục.

Xác minh phiên bản Firebase CLI và firebase-function

Đảm bảo bạn đang dùng ít nhất phiên bản 12.00 của Firebase CLI và phiên bản firebase-functions của 4.3.0. Mọi phiên bản mới hơn đều sẽ hỗ trợ cả thế hệ thứ 2 và thế hệ thứ 1.

Cập nhật các lệnh nhập

Nhập các hàm thế hệ thứ 2 từ gói con v2 trong SDK firebase-functions. Đường dẫn nhập khác này là tất cả những gì Firebase CLI cần để xác định xem có nên triển khai mã hàm của bạn dưới dạng hàm thế hệ thứ nhất hay thế hệ thứ hai hay không.

Gói con v2 có tính mô-đun và bạn chỉ nên nhập mô-đun cụ thể mà bạn cần.

Trước: Thế hệ thứ nhất

const functions = require("firebase-functions/v1");

Sau: Thế hệ thứ 2

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

Cập nhật định nghĩa về điều kiện kích hoạt

Vì SDK thế hệ thứ 2 ưu tiên các lần nhập theo mô-đun, hãy cập nhật các định nghĩa về điều kiện kích hoạt để phản ánh các lần nhập đã thay đổi ở bước trước.

Các đối số được truyền đến lệnh gọi lại cho một số điều kiện kích hoạt đã thay đổi. Trong ví dụ này, xin lưu ý rằng các đối số cho lệnh gọi lại onDocumentCreated đã được hợp nhất thành một đối tượng event duy nhất. Ngoài ra, một số điều kiện kích hoạt có các tính năng cấu hình mới thuận tiện, chẳng hạn như lựa chọn cors của điều kiện kích hoạt onRequest.

Trước: Thế hệ thứ nhất

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

Sau: Thế hệ thứ 2

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

Sử dụng cấu hình có tham số

Các hàm thế hệ thứ 2 ngừng hỗ trợ functions.config để chuyển sang một giao diện an toàn hơn cho việc xác định các tham số cấu hình một cách khai báo trong cơ sở mã nguồn của bạn. Với mô-đun params mới, CLI sẽ chặn việc triển khai trừ phi tất cả các tham số đều có giá trị hợp lệ, đảm bảo rằng một hàm không được triển khai khi thiếu cấu hình.

Di chuyển sang gói con params

Nếu đã sử dụng cấu hình môi trường bằng functions.config, bạn có thể di chuyển cấu hình hiện có sang cấu hình được tham số hoá.

Trước: Thế hệ thứ nhất

const functions = require("firebase-functions/v1");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

Sau: Thế hệ thứ 2

const {onRequest} = require("firebase-functions/v2/https");
const {defineString} = require("firebase-functions/params");

const dateFormat = defineString("DATE_FORMAT");

exports.date = onRequest((req, res) => {
  const date = new Date();
  const formattedDate = date.toLocaleDateString(dateFormat.value());

  // ...
});

Đặt giá trị tham số

Lần đầu tiên bạn triển khai, Firebase CLI sẽ nhắc bạn nhập tất cả các giá trị của tham số và lưu các giá trị đó vào một tệp dotenv. Để xuất các giá trị functions.config, hãy chạy firebase functions:config:export.

Để tăng cường độ an toàn, bạn cũng có thể chỉ định các loại tham số và quy tắc xác thực.

Trường hợp đặc biệt: Khoá API

Mô-đun params tích hợp với Cloud Secret Manager, cung cấp quyền kiểm soát truy cập chi tiết đối với các giá trị nhạy cảm như khoá API. Hãy xem tham số bí mật để biết thêm thông tin.

Trước: Thế hệ thứ nhất

const functions = require("firebase-functions/v1");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});

Sau: Thế hệ thứ 2

const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Define the secret parameter
const apiKey = defineSecret("API_KEY");

exports.getQuote = onRequest(
  // make the secret available to this function
  { secrets: [apiKey] },
  async (req, res) => {
    // retrieve the value of the secret
    const quote = await fetchMotivationalQuote(apiKey.value());
    // ...
  }
);

Đặt các lựa chọn về thời gian chạy

Cấu hình các lựa chọn thời gian chạy đã thay đổi giữa thế hệ thứ nhất và thế hệ thứ hai. Thế hệ thứ hai cũng bổ sung một chức năng mới để đặt các lựa chọn cho tất cả các hàm.

Trước: Thế hệ thứ nhất

const functions = require("firebase-functions/v1");

exports.date = functions
  .runWith({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  })
  // locate function closest to users
  .region("asia-northeast1")
  .https.onRequest((req, res) => {
    // ...
  });

exports.uppercase = functions
  // locate function closest to users and database
  .region("asia-northeast1")
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

Sau: Thế hệ thứ 2

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");

// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });

exports.date = onRequest({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  }, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

Sử dụng tính đồng thời

Một ưu điểm đáng kể của các hàm thế hệ thứ 2 là khả năng của một phiên bản hàm duy nhất có thể xử lý nhiều yêu cầu cùng một lúc. Điều này có thể giảm đáng kể số lần khởi động nguội mà người dùng cuối gặp phải. Theo mặc định, mức độ đồng thời được đặt ở mức 80, nhưng bạn có thể đặt mức này thành bất kỳ giá trị nào từ 1 đến 1000:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

Việc điều chỉnh mức độ đồng thời có thể cải thiện hiệu suất và giảm chi phí cho các hàm. Tìm hiểu thêm về tính đồng thời trong Cho phép các yêu cầu đồng thời.

Kiểm tra việc sử dụng biến toàn cục

Các hàm thế hệ thứ nhất được viết mà không cần quan tâm đến tính đồng thời có thể sử dụng các biến chung được đặt và đọc trên mỗi yêu cầu. Khi tính đồng thời được bật và một phiên bản duy nhất bắt đầu xử lý nhiều yêu cầu cùng lúc, điều này có thể gây ra lỗi trong hàm của bạn vì các yêu cầu đồng thời bắt đầu thiết lập và đọc các biến toàn cục cùng lúc.

Trong khi nâng cấp, bạn có thể đặt CPU của hàm thành gcf_gen1 và đặt concurrency thành 1 để khôi phục hành vi của thế hệ thứ nhất:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});

Tuy nhiên, bạn không nên dùng cách này để khắc phục lâu dài vì nó sẽ làm mất đi những lợi thế về hiệu suất của các hàm thế hệ thứ 2. Thay vào đó, hãy kiểm tra việc sử dụng các biến toàn cục trong các hàm của bạn và xoá các chế độ cài đặt tạm thời này khi bạn đã sẵn sàng.

Di chuyển lưu lượng truy cập sang các hàm thế hệ thứ 2 mới

Giống như khi thay đổi khu vực hoặc loại trình kích hoạt của một hàm, bạn sẽ cần đặt tên mới cho hàm thế hệ thứ 2 và di chuyển lưu lượng truy cập sang hàm đó một cách từ từ.

Bạn không thể nâng cấp một hàm từ thế hệ thứ nhất lên thế hệ thứ hai có cùng tên và chạy firebase deploy. Việc này sẽ dẫn đến lỗi:

Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

Trước khi làm theo các bước này, trước tiên, hãy đảm bảo rằng hàm của bạn là đẳng phương, vì cả phiên bản mới và phiên bản cũ của hàm sẽ chạy cùng lúc trong quá trình thay đổi. Ví dụ: nếu bạn có một hàm thế hệ thứ nhất phản hồi các sự kiện ghi trong Firestore, hãy đảm bảo rằng việc phản hồi một sự kiện ghi hai lần (một lần bằng hàm thế hệ thứ nhất và một lần bằng hàm thế hệ thứ hai) sẽ giúp ứng dụng của bạn ở trạng thái nhất quán.

  1. Đổi tên hàm trong mã hàm. Ví dụ: đổi tên resizeImage thành resizeImageSecondGen.
  2. Triển khai hàm để cả hàm thế hệ thứ nhất ban đầu và hàm thế hệ thứ hai đều đang chạy.
    1. Trong trường hợp có thể gọi, Hàng đợi tác vụ và trình kích hoạt HTTP, hãy bắt đầu trỏ tất cả các ứng dụng đến hàm thế hệ thứ 2 bằng cách cập nhật mã ứng dụng bằng tên hoặc URL của hàm thế hệ thứ 2.
    2. Với các trình kích hoạt ở chế độ nền, cả hàm thế hệ thứ nhất và thế hệ thứ hai sẽ phản hồi mọi sự kiện ngay khi triển khai.
  3. Khi tất cả lưu lượng truy cập đã được di chuyển, hãy xoá hàm thế hệ thứ nhất bằng lệnh firebase functions:delete của Firebase CLI.
    1. Nếu muốn, hãy đổi tên hàm thế hệ thứ 2 cho khớp với tên hàm thế hệ thứ nhất.