Приложениям, использующим функции первого поколения, следует рассмотреть возможность перехода на функции второго поколения, следуя инструкциям в этом руководстве. Функции второго поколения используют Cloud Run для обеспечения лучшей производительности, лучшей конфигурации, лучшего мониторинга и многого другого.
Примеры в этом документе предполагают использование JavaScript с модулями CommonJS ( require импорт стилей), но те же принципы применимы к JavaScript с ESM ( import … from импорта стилей) и TypeScript.
The migration process
Функции первого и второго поколений могут сосуществовать в одном исходном файле. Это позволяет поэтапно переносить код по мере готовности. Однако следует отметить, что такое смешивание пакетов не работает в рамках одной отдельной функции .
Мы рекомендуем переносить функции по одной, проводя тестирование и проверку перед продолжением.
Проверьте версии Firebase CLI и firebase-functions .
Убедитесь, что вы используете как минимум Firebase CLI версии 12.00 и firebase-functions версии 4.3.0 . Более новые версии будут поддерживать как первое, так и второе поколение.
Update imports
Функции второго поколения импортируются из подпакета v2 в SDK firebase-functions . Этот другой путь импорта — всё, что нужно Firebase CLI, чтобы определить, следует ли развертывать код вашей функции как функцию первого или второго поколения.
Подпакет v2 имеет модульную структуру, и мы рекомендуем импортировать только тот конкретный модуль, который вам необходим.
Before: 1st gen
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");
Update trigger definitions
Поскольку SDK второго поколения предпочитает модульный импорт, обновите определения триггеров, чтобы отразить изменения в импорте, внесенные на предыдущем шаге.
Изменились аргументы, передаваемые в функции обратного вызова для некоторых триггеров. В этом примере обратите внимание, что аргументы функции обратного вызова onDocumentCreated объединены в один объект event . Кроме того, некоторые триггеры получили новые удобные функции конфигурации, например, параметр cors для триггера onRequest .
Before: 1st gen
const functions = require("firebase-functions/v1");
exports.date = functions.https.onRequest((req, res) => {
// ...
});
exports.uppercase = functions.firestore
.document("my-collection/{docId}")
.onCreate((change, context) => {
// ...
});
After: 2nd gen
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 для извлечения этих свойств непосредственно в сигнатуре обработчика, сводя к минимуму необходимость переписывания логики функции.
Provider mapping reference
| Поставщик | 1st gen Arguments | 2nd gen Patched Event Destructuring |
| Pub/Sub | (message, context) | ({ message, context }) => { ... } |
| Cloud Firestore | (snapshot, context) | ({ snapshot, context }) => { ... } |
| Cloud Storage | (object, context) | ({ object, context }) => { ... } |
| Realtime Database | (snapshot, context) | ({ snapshot, context }) => { ... } |
| Remote Config | (version, context) | ({ version, context }) => { ... } |
| Cloud Scheduler | (context) | ({ context }) => { ... } |
| Очередь задач | (data, context) | ({ data, context }) => { ... } |
Before (1st gen):
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
const data = message.json;
const eventId = context.eventId;
// ... rest of the logic
});
New Alternative (2nd gen with Destructuring):
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
});
Use parameterized configuration
Функции второго поколения отказываются от поддержки functions.config в пользу более безопасного интерфейса для декларативного определения параметров конфигурации внутри вашего кода. С новым модулем params CLI блокирует развертывание, если все параметры не имеют допустимого значения, гарантируя, что функция не будет развернута с отсутствующей конфигурацией.
Before: 1st gen
const functions = require("firebase-functions/v1");
exports.getQuote = functions.https.onRequest(async (req, res) => {
const quote = await fetchMotivationalQuote(functions.config().apiKey);
// ...
});
After: 2nd gen
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. Настоятельно рекомендуется использовать этот способ как наиболее эффективный и безопасный.
Export configuration with the 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```Update function code to bind secrets
Чтобы использовать конфигурацию, хранящуюся в новом секрете в 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; // ... });Deploy Functions
Разверните обновленные функции, чтобы применить изменения и привязать секретные разрешения.
firebase deploy --only functions:<your-function-name>
Set runtime options
Изменилась конфигурация параметров среды выполнения между 1-м и 2-м поколениями. Во 2-м поколении также добавлена новая возможность устанавливать параметры для всех функций.
Before: 1st gen
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) => {
// ...
});
After: 2nd gen
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) => {
/* ... */
});
Update default service account (optional)
В то время как функции первого поколения используют учетную запись службы 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-го поколения).
Use concurrency
Существенным преимуществом функций второго поколения является возможность обработки одним экземпляром функции более одного запроса одновременно. Это может значительно сократить количество холодных запусков, с которыми сталкиваются конечные пользователи. По умолчанию параметр параллельного выполнения установлен на 80, но вы можете установить его на любое значение от 1 до 1000:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// set concurrency value
concurrency: 500
},
(req, res) => {
// ...
});
Настройка параллельного выполнения может повысить производительность и снизить стоимость функций. Подробнее о параллельном выполнении см. в разделе «Разрешить одновременные запросы» .
Audit global variable usage
Функции первого поколения, написанные без учета параллельного выполнения, могут использовать глобальные переменные, которые устанавливаются и считываются при каждом запросе. Когда параллельное выполнение включено и один экземпляр начинает обрабатывать несколько запросов одновременно, это может привести к ошибкам в вашей функции, поскольку параллельные запросы начинают устанавливать и считывать глобальные переменные одновременно.
В процессе обновления вы можете установить для своей функции значение ЦП 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) => {
// ...
});
Однако это не рекомендуется в качестве долгосрочного решения, поскольку оно сводит на нет преимущества в производительности функций второго поколения. Вместо этого проведите аудит использования глобальных переменных в ваших функциях и удалите эти временные настройки, когда будете готовы.
Migrate traffic to the new 2nd gen functions
Как и при изменении региона или типа триггера функции , вам потребуется дать функции второго поколения новое имя и постепенно перенаправлять на неё трафик.
Невозможно обновить функцию с первого поколения до второго с тем же именем и запустить firebase deploy . Попытка сделать это приведет к ошибке:
Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.
Стратегия миграции зависит от типа триггера, используемого вашей функцией.
Migrate Callable, Task Queue, and HTTP triggers
Эти триггеры являются прямыми вызовами. Поскольку функция второго поколения будет иметь новое имя (и новый URL для HTTP-триггеров), вы можете перенести трафик, обновив клиенты.
- Переименуйте функцию в своем коде (например, переименуйте
myCallableвmyCallableV2). - Разверните функцию. Теперь работают как функция первого, так и второго поколения.
- Обновите клиентский код или вызывающую функцию, чтобы она указывала на имя или URL-адрес новой функции второго поколения.
- После того, как весь трафик будет перенаправлен на новую функцию, удалите функцию первого поколения, используя команду
firebase functions:deleteв Firebase CLI.
Migrate background triggers
Фоновые триггеры (такие как триггеры Pub/Sub , Cloud Firestore и Cloud Storage ) реагируют на события в вашем проекте. Чтобы не пропустить ни одного события во время перехода, необходимо временно запускать функции первого и второго поколений одновременно.
В течение переходного периода обе функции будут запускаться при одном и том же событии. Это означает, что ваша бизнес-логика будет выполняться дважды при каждом событии. Перед продолжением убедитесь, что ваша функция идемпотентна .
Добавьте функцию второго поколения рядом с функцией первого поколения, сохранив при этом существующую функцию первого поколения в вашем коде и добавив функцию второго поколения, которая будет прослушивать тот же источник событий.
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); });Выполните команду
firebase deploy. Обе функции теперь активны и прослушивают одни и те же события.Убедитесь, что функция второго поколения получает трафик. Отслеживайте журналы обеих функций. Убедитесь, что функция второго поколения вызывается для всех событий и что вызовы выполняются успешно.
Как только вы убедитесь, что функция работает корректно, перенесите фактическую бизнес-логику из функции первого поколения в тело функции второго поколения. Если вы использовали метод сквозной передачи, удалите вызов
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 ... });Deploy this change.
Удалите определение функции первого поколения из своего кода и выполните повторное развертывание. Интерфейс командной строки предложит вам удалить функцию первого поколения из Google Cloud .