目前使用第 1 代函式的應用程式,應考慮按照本指南中的操作說明,遷移至第 2 代。第 2 代函式會使用 Cloud Run 提供更優異的效能、更完善的設定和監控功能等。
本頁的範例假設您使用 JavaScript 搭配 CommonJS 模組 (require
樣式匯入),但同樣的原則也適用於 JavaScript 搭配 ESM (import … from
樣式匯入) 和 TypeScript。
遷移程序
第 1 代和第 2 代函式可在同一檔案中並存。這樣一來,您就可以在準備就緒時,輕鬆逐一遷移。建議您一次遷移一個函式,並在繼續前執行測試和驗證。
確認 Firebase CLI 和 firebase-function
版本
請確認您至少使用 Firebase CLI 版本 12.00
和 firebase-functions
版本 4.3.0
。任何較新的版本都會支援第 2 代和第 1 代。
更新匯入作業
第 2 代函式會從 firebase-functions
SDK 中的 v2
子套件匯入。Firebase CLI 需要透過這個不同的匯入路徑,判斷是否要將函式程式碼部署為第 1 代或第 2 代函式。
v2
子套件是模組化,建議您只匯入所需的特定模組。
變更前:第 1 代
const functions = require("firebase-functions/v1");
變更後:第 2 代
// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
更新觸發條件定義
由於第 2 代 SDK 偏好模組化匯入,請更新觸發條件定義,以反映上一個步驟中變更的匯入項目。
部分觸發事件傳遞至回呼的引數已變更。請注意,在這個範例中,onDocumentCreated
回呼的引數已整合為單一 event
物件。此外,部分觸發條件提供方便的新設定功能,例如 onRequest
觸發條件的 cors
選項。
變更前:第 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) => {
// ...
});
變更後:第 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) => {
/* ... */
});
使用參數化設定
第 2 代函式已不再支援 functions.config
,改為採用更安全的介面,以便在程式碼集內以宣告方式定義設定參數。有了新的 params
模組,CLI 會阻擋部署作業,除非所有參數都有有效值,以確保不會在缺少設定的情況下部署函式。
遷移至 params
子套件
如果您一直使用含有 functions.config
的環境設定,可以將現有設定遷移至參數化設定。
變更前:第 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);
// ...
});
變更後:第 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());
// ...
});
設定參數值
第一次部署時,Firebase CLI 會提示您輸入所有參數值,並將這些值儲存在 dotenv 檔案中。如要匯出 functions.config 值,請執行 firebase functions:config:export
。
特殊情況:API 金鑰
params
模組會與 Cloud Secret Manager 整合,為 API 金鑰等機密值提供精細的存取權控管機制。詳情請參閱密鑰參數。
變更前:第 1 代
const functions = require("firebase-functions/v1");
exports.getQuote = functions.https.onRequest(async (req, res) => {
const quote = await fetchMotivationalQuote(functions.config().apiKey);
// ...
});
變更後:第 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());
// ...
}
);
設定執行階段選項
第 1 代和第 2 代之間的執行階段選項設定有所不同。第 2 代也新增了可為所有函式設定選項的新功能。
變更前:第 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) => {
// ...
});
變更後:第 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) => {
/* ... */
});
使用並行
第 2 代函式的一大優勢,就是單一函式執行個體可同時處理多個要求。這麼做可以大幅減少使用者遇到冷啟動的問題次數。根據預設,並行作業會設為 80,但您可以將其設為 1 到 1000 之間的任何值:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// set concurrency value
concurrency: 500
},
(req, res) => {
// ...
});
調整並行作業可提升函式的效能並降低成本。如要進一步瞭解並行處理,請參閱「允許並行要求」。
稽核全域變數使用情形
第一代函式在編寫時未考量並行性,因此可能會使用在每次要求中設定及讀取的全域變數。啟用並行處理功能後,單一例項會開始同時處理多項要求,這可能會導致並行要求同時設定及讀取全域變數,進而導致函式出現錯誤。
升級時,您可以將函式的 CPU 設為 gcf_gen1
,並將 concurrency
設為 1,以還原第 1 代行為:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// TEMPORARY FIX: remove concurrency
cpu: "gcf_gen1",
concurrency: 1
},
(req, res) => {
// ...
});
不過,我們不建議您長期採用這個做法,因為這會失去第 2 代函式的效能優勢。請改為稽核函式中全域變數的用法,並在準備就緒時移除這些暫時性設定。
將流量遷移至新的第 2 代函式
就像變更函式的區域或觸發事件類型一樣,您需要為第 2 代函式命名,並逐步將流量遷移至該函式。
您無法將函式從第 1 代升級至第 2 代,並使用相同名稱執行 firebase deploy
。這麼做會導致錯誤:
Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.
在您按照這些步驟操作之前,請先確認您的函式是否冪等,因為在變更期間,函式的新舊版本都會同時執行。舉例來說,如果您有第 1 代函式可回應 Firestore 中的寫入事件,請確保在回應這些事件時,第 1 代函式和第 2 代函式會分別回應寫入事件兩次,以便讓應用程式維持一致的狀態。
- 在函式程式碼中重新命名函式。例如,將
resizeImage
重新命名為resizeImageSecondGen
。 - 部署函式,讓原本的第 1 代函式和第 2 代函式都執行。
- 在可呼叫、工作佇列和 HTTP 觸發事件的情況下,請使用第 2 代函式的名稱或網址更新用戶端程式碼,開始將所有用戶端指向第 2 代函式。
- 使用背景觸發條件時,第 1 代和第 2 代函式都會在部署後立即回應每個事件。
- 當所有流量都遷移完畢後,請使用 Firebase CLI 的
firebase functions:delete
指令刪除第 1 代函式。- 您可以視需要重新命名第 2 代函式,使其與第 1 代函式的名稱相符。