Приложениям, использующим функции первого поколения, следует рассмотреть возможность перехода на функции второго поколения, следуя инструкциям в этом руководстве. Функции второго поколения используют Cloud Run для обеспечения лучшей производительности, лучшей конфигурации, лучшего мониторинга и многого другого.
Примеры в этом документе предполагают использование JavaScript с модулями CommonJS ( require импорт стилей), но те же принципы применимы к JavaScript с ESM ( import … from импорта стилей) и TypeScript.
миграционный процесс
Функции первого и второго поколений могут сосуществовать в одном файле. Это позволяет переносить код по частям по мере готовности. Мы рекомендуем переносить функции по одной, проводя тестирование и проверку перед продолжением.
Проверьте версии Firebase CLI и firebase-function .
Убедитесь, что вы используете как минимум Firebase CLI версии 12.00 и firebase-functions версии 4.3.0 . Более новые версии будут поддерживать как первое, так и второе поколение.
Обновить импорты
Функции второго поколения импортируются из подпакета v2 в SDK firebase-functions . Этот другой путь импорта — всё, что нужно Firebase CLI, чтобы определить, следует ли развертывать код вашей функции как функцию первого или второго поколения.
Подпакет 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");
Обновить определения триггеров
Поскольку SDK второго поколения предпочитает модульный импорт, обновите определения триггеров, чтобы отразить изменения в импорте, внесенные на предыдущем шаге.
Изменились аргументы, передаваемые в функции обратного вызова для некоторых триггеров. В этом примере обратите внимание, что аргументы функции обратного вызова onDocumentCreated объединены в один объект event . Кроме того, некоторые триггеры получили новые удобные функции конфигурации, например, параметр cors для триггера onRequest .
Ранее: 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) => {
/* ... */
});
Сведите к минимуму усилия по переписыванию кода с помощью деструктуризации JavaScript.
Если ваши функции имеют сложные тела, которые в значительной степени зависят от контекста первого поколения или параметров, специфичных для поставщика (например, message или snapshot ), вы можете использовать вспомогательные средства совместимости первого поколения, встроенные в SDK второго поколения.
SDK второго поколения автоматически добавляет в объект события геттеры, соответствующие сигнатурам первого поколения. Это позволяет использовать деструктуризацию JavaScript для извлечения этих свойств непосредственно в сигнатуре обработчика, сводя к минимуму необходимость переписывания логики функции.
Справочник по сопоставлению поставщиков
| Поставщик | Аргументы первого поколения | 2-е поколение, исправленная деструктуризация событий |
| Паб/Саб | (message, context) | ({ message, context }) => { ... } |
| Магазин огней | (snapshot, context) | ({ snapshot, context }) => { ... } |
| Хранилище | (object, context) | ({ object, context }) => { ... } |
| База данных реального времени | (snapshot, context) | ({ snapshot, context }) => { ... } |
| Удалённая конфигурация | (version, context) | ({ version, context }) => { ... } |
| Планировщик | (context) | ({ context }) => { ... } |
| Очередь задач | (data, context) | ({ data, context }) => { ... } |
До (1-е поколение):
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
const data = message.json;
const eventId = context.eventId;
// ... rest of the logic
});
Новая альтернатива (2-е поколение с деструктуризацией):
import { onMessagePublished } from "firebase-functions/v2/pubsub";
export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
// No need to change the function body!
const data = message.json; // Uses v1 Message wrapper
const eventId = context.eventId; // Uses v1 EventContext map
// ... rest of the logic
});
Используйте параметризованную конфигурацию
Функции второго поколения отказываются от поддержки functions.config в пользу более безопасного интерфейса для декларативного определения параметров конфигурации внутри вашего кода. С новым модулем params CLI блокирует развертывание, если все параметры не имеют допустимого значения, гарантируя, что функция не будет развернута с отсутствующей конфигурацией.
Ранее: 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());
// ...
}
);
Если у вас уже есть конфигурация среды с functions.config , перенесите эту конфигурацию в рамках обновления до версии 2-го поколения.
API functions.config устарел и будет выведен из эксплуатации в марте 2027 года. После этой даты развертывание с использованием functions.config будет завершаться с ошибкой.
Чтобы предотвратить сбои при развертывании, перенесите свою конфигурацию в Cloud Secret Manager с помощью Firebase CLI. Настоятельно рекомендуется использовать этот способ как наиболее эффективный и безопасный.
Экспорт конфигурации с помощью Firebase CLI
Используйте команду
config export, чтобы экспортировать существующую конфигурацию среды в новый секрет в Cloud Secret Manager:$ firebase functions:config:export i This command retrieves your Runtime Config values (accessed via functions.config()) and exports them as a Secret Manager secret. i Fetching your existing functions.config() from your project... ✔ Fetched your existing functions.config(). i Configuration to be exported: ⚠ This may contain sensitive data. Do not share this output. { ... } ✔ What would you like to name the new secret for your configuration? RUNTIME_CONFIG ✔ Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```Обновите код функции для привязки секретов.
Чтобы использовать конфигурацию, хранящуюся в новом секрете в Cloud Secret Manager, используйте API
defineJsonSecretв источнике вашей функции. Также убедитесь, что секреты привязаны ко всем функциям, которым они необходимы.До
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });После
const { onRequest } = require("firebase-functions/v2/https"); const { defineJsonSecret } = require("firebase-functions/params"); const config = defineJsonSecret("RUNTIME_CONFIG"); exports.myFunction = onRequest( // Bind secret to your function { secrets: [config] }, (req, res) => { // Access secret values via .value() const apiKey = config.value().someapi.key; // ... });Развертывание функций
Разверните обновленные функции, чтобы применить изменения и привязать секретные разрешения.
firebase deploy --only functions:<your-function-name>
Задайте параметры выполнения
Изменилась конфигурация параметров среды выполнения между 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) => {
/* ... */
});
Обновить учетную запись службы по умолчанию (необязательно)
В то время как функции первого поколения используют учетную запись службы Google App Engine по умолчанию для авторизации доступа к API Firebase, функции второго поколения используют учетную запись службы Compute Engine по умолчанию. Это различие может привести к проблемам с разрешениями для функций, перенесенных на второе поколение, в случаях, когда вы предоставили специальные разрешения учетной записи службы первого поколения. Если вы не изменяли разрешения учетной записи службы, вы можете пропустить этот шаг.
Рекомендуемое решение — явно назначить существующую учетную запись службы App Engine по умолчанию первого поколения функциям, которые вы хотите перенести на второе поколение, переопределив значение по умолчанию второго поколения. Это можно сделать, убедившись, что каждая перенесенная функция устанавливает правильное значение для 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) => {
// ...
});
В качестве альтернативы вы можете убедиться, что изменили данные учетной записи службы таким образом, чтобы они соответствовали всем необходимым разрешениям как для учетной записи службы App Engine по умолчанию (для 1-го поколения), так и для учетной записи службы Compute Engine по умолчанию (для 2-го поколения).
Используйте параллельное выполнение.
Существенным преимуществом функций второго поколения является возможность обработки одним экземпляром функции более одного запроса одновременно. Это может значительно сократить количество холодных запусков, с которыми сталкиваются конечные пользователи. По умолчанию параметр параллельного выполнения установлен на 80, но вы можете установить его на любое значение от 1 до 1000:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// set concurrency value
concurrency: 500
},
(req, res) => {
// ...
});
Настройка параллельного выполнения может повысить производительность и снизить стоимость функций. Подробнее о параллельном выполнении см. в разделе «Разрешить одновременные запросы» .
Проверка использования глобальных переменных
Функции первого поколения, написанные без учета параллельного выполнения, могут использовать глобальные переменные, которые устанавливаются и считываются при каждом запросе. Когда параллельное выполнение включено и один экземпляр начинает обрабатывать несколько запросов одновременно, это может привести к ошибкам в вашей функции, поскольку параллельные запросы начинают устанавливать и считывать глобальные переменные одновременно.
В процессе обновления вы можете установить для своей функции значение ЦП gcf_gen1 и параметр concurrency равным 1, чтобы восстановить поведение первого поколения:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// TEMPORARY FIX: remove concurrency
cpu: "gcf_gen1",
concurrency: 1
},
(req, res) => {
// ...
});
Однако это не рекомендуется в качестве долгосрочного решения, поскольку оно сводит на нет преимущества в производительности функций второго поколения. Вместо этого проведите аудит использования глобальных переменных в ваших функциях и удалите эти временные настройки, когда будете готовы.
Перенаправьте трафик на новые функции второго поколения.
Как и при изменении региона или типа триггера функции , вам потребуется дать функции второго поколения новое имя и постепенно перенаправлять на неё трафик.
Невозможно обновить функцию с первого поколения до второго с тем же именем и запустить firebase deploy . Попытка сделать это приведет к ошибке:
Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.
Стратегия миграции зависит от типа триггера, используемого вашей функцией.
Для вызываемых объектов, очередей задач и HTTP-триггеров
Эти триггеры являются прямыми вызовами. Поскольку функция второго поколения будет иметь новое имя (и новый URL для HTTP-триггеров), вы можете перенести трафик, обновив клиенты.
- Переименуйте функцию в своем коде (например, переименуйте
myCallableвmyCallableV2). - Разверните функцию. Теперь работают как функция первого, так и второго поколения.
- Обновите клиентский код или вызывающую функцию, чтобы она указывала на имя или URL-адрес новой функции второго поколения.
- После того, как весь трафик будет перенаправлен на новую функцию, удалите функцию первого поколения, используя команду
firebase functions:deleteв Firebase CLI.
Для фоновых триггеров ( Pub/Sub , Cloud Firestore , Cloud Storage и т. д.)
Фоновые триггеры реагируют на события в вашем проекте. Чтобы не пропустить ни одного события во время перехода, необходимо временно запускать функции первого и второго поколений одновременно.
В течение переходного периода обе функции будут запускаться при одном и том же событии. Это означает, что ваша бизнес-логика будет выполняться дважды при каждом событии. Перед продолжением убедитесь, что ваша функция идемпотентна .
Шаг 1: Добавьте функцию второго поколения рядом с функцией первого поколения.
Сохраните существующую функцию первого поколения в своем коде и добавьте функцию второго поколения, которая будет прослушивать тот же источник событий.
Полезный совет: используйте сквозную передачу для проверки. Чтобы избежать дублирования бизнес-логики в коде во время перехода или чтобы убедиться, что функция второго поколения корректно получает события, прежде чем полностью ей доверять, сделайте функцию второго поколения сквозной, которая вызывает функцию первого поколения с помощью метода run .
import * as functions from "firebase-functions/v1";
import { onMessagePublished } from "firebase-functions/v2/pubsub";
// --- Existing 1st gen function ---
export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => {
console.log("V1 handler running for event:", context.eventId);
// ... existing v1 function logic ...
});
// --- New v2 passthrough function ---
export const myPubSubV2 = onMessagePublished("my-topic", async ({ message, context }) => {
console.log("v2 handler triggering V1 for event:", context.eventId);
// Call the v1 function's handler
await myPubSub.run(message, context);
});
Шаг 2: Разверните обе функции.
Выполните команду firebase deploy . Обе функции теперь активны и прослушивают одни и те же события.
Шаг 3: Убедитесь, что функция второго поколения принимает трафик.
Отслеживайте журналы обеих функций. Убедитесь, что функция второго поколения вызывается для всех событий и что вызовы выполняются успешно.
Шаг 4: Перенесите всю логику во вторую функцию.
Когда убедитесь в правильности решения, перенесите фактическую бизнес-логику из функции первого поколения в тело функции второго поколения. Если вы использовали метод сквозной передачи, удалите вызов myPubSub.run() .
import * as functions from "firebase-functions/v1";
import { onMessagePublished } from "firebase-functions/v2/pubsub";
// --- Existing v1 function (to be removed next) ---
export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => {
console.log("v1 handler running for event:", context.eventId);
// ... existing v1 function logic ...
});
// --- New v2 function with full logic ---
export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
console.log("v2 handler running for event:", context.eventId);
// ... existing v1 function logic WAS MOVED HERE ...
});
Внедрите это изменение.
Шаг 5: Удалите функцию первого поколения.
Удалите определение функции первого поколения из своего кода и выполните повторное развертывание. Интерфейс командной строки предложит вам удалить функцию первого поколения из Google Cloud.
import { onMessagePublished } from "firebase-functions/v2/pubsub";
// --- V1 function definition REMOVED ---
// --- New v2 function with full logic ---
export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
console.log("v2 handler running for event:", context.eventId);
// ... existing v1 function logic ...
});