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

Những ứng dụng đang dùng các hàm thế hệ 1 nên cân nhắc chuyển sang thế hệ 2 bằng cách làm theo các bước trong hướng dẫn này. Các hàm thế hệ 2 sử dụng Cloud Run để cung cấp hiệu suất tốt hơn, cấu hình tốt hơn, giám sát tốt hơn và nhiều tính năng khác.

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

Quá trình di chuyển

Các hàm thế hệ 1 và thế hệ 2 có thể cùng tồn tại cạnh nhau trong cùng một tệp. Chiến dịch này cho phép di chuyển dễ dàng từng phần khi bạn đã 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 sử dụng Firebase CLI phiên bản 12.00firebase-functions phiên bản 4.3.0. Mọi phiên bản mới hơn đều sẽ hỗ trợ thế hệ thứ 2 dưới dạng thế hệ 1.

Cập nhật 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ì Giao diện dòng lệnh (CLI) của Firebase cần để xác định xem triển khai mã hàm của bạn dưới dạng hàm thế hệ 1 hoặc thế hệ 2.

Gói con v2 là theo mô-đun và bạn chỉ nên nhập mà bạn cần.

Trước: thế hệ thứ 1

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

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 của điều kiện kích hoạt

Vì SDK thế hệ thứ 2 ưu tiên tính năng nhập mô-đun, hãy cập nhật định nghĩa của điều kiện kích hoạt thành phản ánh các lệnh 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 phần này Ví dụ: xin lưu ý rằng các đối số cho lệnh gọi lại onDocumentCreated đã được được hợp nhất thành một đối tượng event duy nhất. Ngoài ra, một số trình 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ư cors của điều kiện kích hoạt onRequest .

Trước: thế hệ thứ 1

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

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ệ 2 ngừng hỗ trợ functions.config và thay vào đó là một giao diện an toàn hơn để xác định các tham số cấu hình theo cách khai báo bên trong cơ sở mã của bạn. Với mô-đun params mới, CLI chặn hoạt động triển khai trừ phi tất cả tham số đều có giá trị hợp lệ, đảm bảo rằng một hàm sẽ không được triển khai khi thiếu cấu hình.

Di chuyển sang gói con params

Nếu đang 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 tại của mình sang cấu hình có tham số.

Trước: thế hệ thứ 1

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

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ị thông số

Trong lần đầu tiên bạn triển khai, Firebase CLI sẽ nhắc đối với tất cả các giá trị của và lưu các giá trị vào tệp dotenv. Để xuất các giá trị function.config, chạy firebase functions:config:export.

Để tăng mức độ an toàn, bạn cũng có thể chỉ định 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, mô-đun này cung cấp kiểm soát quyền truy cập chi tiết vào các giá trị nhạy cảm như khoá API. Xem tham số bí mật để biết thêm thông tin.

Trước: thế hệ thứ 1

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

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 tuỳ chọn thời gian chạy

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

Trước: thế hệ thứ 1

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

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) => {
  /* ... */
});

Dùng mô hình đồng thời

Một lợi thế quan trọng của hàm thế hệ 2 là khả năng của một hàm duy nhất phân phối nhiều yêu cầu cùng một lúc. Điều này có thể làm 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ô hình đồng thời là đặt ở 80, nhưng bạn có thể đặt 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ô hình đồng thời có thể cải thiện hiệu suất và giảm chi phí của các hàm. Tìm hiểu thêm về tính năng đồng thời trong phần 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ệ 1 được viết mà không lưu ý đến mô hình đồng thời có thể sử dụng các biến toàn cục được đặt và đọc trên mỗi yêu cầu. Khi tính năng đồng thời được bật và một thực thể bắt đầu xử lý nhiều yêu cầu cùng một lúc nên có thể gây ra lỗi trong hàm của bạn khi các yêu cầu đồng thời sẽ bắt đầu cài đặt và đọc các biến toàn cục đồng thời.

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ệ 1:

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

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

Tuy nhiên, đây không phải là biện pháp khắc phục lâu dài vì sẽ mất các 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 trong các hàm của bạn và xoá các 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

Tương tự như khi thay đổi vùng hoặc loại điều kiện kích hoạt của một hàm, bạn cần đặt tên mới cho hàm thế hệ 2 và từ từ di chuyển lưu lượng truy cập đến hàm đó.

Bạn không thể nâng cấp một hàm từ thế hệ 1 lên thế hệ 2 có cùng tên rồi chạy firebase deploy. Thao tá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 thực hiện các bước này, đầu tiên hãy đảm bảo rằng hàm của bạn không thay đổi 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ệ 1 phản hồi để ghi các sự kiện trong Firestore, hãy đảm bảo rằng việc phản hồi lệnh ghi hai lần, một lần ở hàm thế hệ 1 và một lần ở hàm thế hệ 2, để phản hồi những sự kiện đó, ứng dụng của bạn sẽ ở 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 này để cả hàm thế hệ 1 và thế hệ 2 ban đầu đề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ả máy khách đến hàm thế hệ 2 bằng cách cập nhật mã máy khách với tên hoặc URL của hàm thế hệ 2.
    2. Với điều kiện kích hoạt ở chế độ nền, cả hàm thế hệ 1 và thế hệ 2 đều 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 bị tắt, hãy xoá hàm thế hệ 1 bằng lệnh firebase functions:delete của firebase CLI.
    1. Bạn có thể đổi tên hàm thế hệ 2 để khớp với tên của hàm thế hệ 1 (không bắt buộc).