Nâng cấp các chức năng Node.js thế hệ 1 lên thế hệ 2

Các ứng dụng hiện đang sử dụng các chức năng thế hệ 1 nên cân nhắc việc chuyển sang thế hệ 2 bằng cách sử dụng hướng dẫn trong hướng dẫn này. Các chức năng thế hệ 2 sử dụng Cloud Run để mang lại 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.v.

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

Quá trình di cư

Các hàm thế hệ 1 và thế hệ 2 có thể cùng tồn tại trong cùng một tệp. Điều này cho phép di chuyển dễ dàng từng phần một khi bạn đã sẵn sàng. Chúng tôi khuyên bạn nên di chuyển từng chức năng một, thực hiện kiểm tra 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 ít nhất Firebase CLI phiên bản 12.00firebase-functions phiên bản 4.3.0 . Bất kỳ phiên bản mới hơn nào cũng sẽ hỗ trợ thế hệ thứ 2 cũng như thế hệ thứ nhất.

Cập nhật nhập khẩu

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

Gói con v2 là mô-đun và chúng tôi khuyên 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");

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 trình kích hoạt

Vì SDK thế hệ 2 ưu tiên nhập mô-đun nên hãy cập nhật định nghĩa trình kích hoạt để phản ánh nội dung nhập đã thay đổi từ bước trước.

Các đối số được chuyển đến lệnh gọi lại cho một số trình kích hoạt đã thay đổi. Trong ví dụ này, hãy 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ố trình kích hoạt có các tính năng cấu hình mới tiện lợi, như tùy chọn cors của trình kích hoạt onRequest .

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

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 tham số hóa

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

Di chuyển sang gói con params

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

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

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ị tham số

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

Để an toàn hơ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: Khóa API

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

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

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

Cấu hình của các tùy chọn thời gian chạy đã thay đổi giữa thế hệ thứ 1 và thứ 2. Thế hệ thứ 2 cũng bổ sung thêm khả năng mới để thiết lập các tùy chọn cho tất cả các chức năng.

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

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

Sử dụng đồng thời

Một lợi thế đáng kể của hàm thế hệ 2 là khả năng của một phiên bản hàm duy nhất có thể phục vụ 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, tính đồng thời được đặt ở mức 80, nhưng bạn có thể đặt nó 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) => {
    // ...
});

Điều chỉnh đồng thời có thể cải thiện hiệu suất và giảm chi phí của các chức năng. Tìm hiểu thêm về tính đồng thời trong Cho phép 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 tính đến tính đồng thời có thể sử dụng các biến toàn cục được đặt và đọc theo từng yêu cầu. Khi tính năng đồng thời được bật và một phiên bản bắt đầu xử lý nhiều yêu cầu cùng một lúc, điều này có thể gây ra lỗi trong hàm của bạn khi các yêu cầu đồng thời bắt đầu thiết lập và đọc các biến chung cùng một lúc.

Trong khi nâng cấp, bạn có thể đặt CPU của chức năng của mình thành gcf_gen1 và đặt concurrency thành 1 để khôi phục hành vi 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à giải pháp khắc phục lâu dài được khuyến nghị vì nó làm mất đi lợi thế về hiệu suất của các chức năng thế hệ 2. Thay vào đó, hãy kiểm tra việc sử dụng các biến chung trong hàm của bạn và xóa 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 chức năng thế hệ thứ 2 mới

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

Không thể nâng cấp chức năng từ thế hệ thứ 1 lên thế hệ thứ 2 có cùng tên và chạy firebase deploy . Làm như vậ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 bạn 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à idempotent , 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ó hàm thế hệ 1 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 ghi hai lần, một lần bởi hàm thế hệ 1 và một lần bởi hàm thế hệ 2, để phản hồi những sự kiện đó sẽ khiến ứng dụng của bạn rơi vào tình trạng trạng thái nhất quán.

  1. Đổi tên hàm trong mã hàm của bạn. Ví dụ: đổi tên thay resizeImage thành resizeImageSecondGen .
  2. Triển khai chức năng để cả chức năng thế hệ thứ 1 ban đầu và chức năng thế hệ thứ 2 đều 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 trình kích hoạt nền, cả chức năng thế hệ thứ 1 và thế hệ thứ 2 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 xóa hàm thế hệ 1 bằng cách sử dụng lệnh firebase functions:delete của firebase CLI.
    1. Tùy chọn đổi tên hàm thế hệ 2 để khớp với tên của hàm thế hệ 1.