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ứ 1
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ứ 1
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 xác định các thông số cấu hình một cách 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ừ 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 với functions.config
, bạn có thể di chuyển cấu hình hiện có bằng cách tái cấu trúc cấu hình đó thành cấu hình được tham số hoá. Ví dụ:
Trước: Thế hệ thứ 1
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ứ 1
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ứ 1
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) => {
/* ... */
});
Cập nhật tài khoản dịch vụ mặc định (không bắt buộc)
Mặc dù các hàm thế hệ thứ nhất sử dụng tài khoản dịch vụ mặc định của Google App Engine để uỷ quyền truy cập vào các API của Firebase, nhưng các hàm thế hệ thứ hai sử dụng tài khoản dịch vụ mặc định của Compute Engine. Sự khác biệt này có thể dẫn đến các vấn đề về quyền đối với những hàm được di chuyển sang thế hệ thứ 2 trong trường hợp bạn đã cấp các quyền đặc biệt cho tài khoản dịch vụ thế hệ thứ 1. Nếu chưa thay đổi bất kỳ quyền nào của tài khoản dịch vụ, bạn có thể bỏ qua bước này.
Giải pháp được đề xuất là chỉ định rõ ràng tài khoản dịch vụ mặc định hiện có của App Engine thế hệ thứ nhất cho các hàm mà bạn muốn di chuyển sang thế hệ thứ hai, ghi đè giá trị mặc định của thế hệ thứ hai. Bạn có thể thực hiện việc này bằng cách đảm bảo mỗi hàm đã di chuyển đều đặt giá trị chính xác cho serviceAccountEmail
:
const {onRequest} = require("firebase-functions/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions");
// Use the App Engine default service account for all functions
setGlobalOptions({serviceAccountEmail: '<my-project-number>@<wbr>appspot.gserviceaccount.com'});
// Now I use the App Engine default service account.
exports.date = onRequest({cors: true}, (req, res) => {
// ...
});
// I do too!
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
// ...
});
Ngoài ra, bạn có thể đảm bảo sửa đổi thông tin tài khoản dịch vụ để khớp với tất cả các quyền cần thiết trên cả tài khoản dịch vụ mặc định của App Engine (cho Thế hệ thứ nhất) và tài khoản dịch vụ mặc định của Compute Engine (cho Thế hệ thứ hai).
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 ở 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ứ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 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ệ thứ nhất được viết mà không tính đế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á những 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
. 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 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) để phản hồi các sự kiện đó sẽ giúp ứng dụng của bạn ở trạng thái nhất quán.
- Đổi tên hàm trong mã hàm. Ví dụ: đổi tên
resizeImage
thànhresizeImageSecondGen
. - 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.
- 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.
- 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.
- 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.- 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.