Приложения, в которых используются функции первого поколения, следует перевести на функции второго поколения, следуя инструкциям из этого руководства. Функции второго поколения используют Cloud Run, чтобы обеспечить более высокую производительность, более удобную конфигурацию и мониторинг, а также многое другое.
В примерах в этом документе предполагается, что вы используете JavaScript с модулями CommonJS (импорт в стиле require), но те же принципы применяются к JavaScript с ESM (импорт в стиле import … from) и TypeScript.
Процесс переноса
Функции первого и второго поколений могут быть в одном исходном файле. Это позволит вам переносить базу кода по частям, когда вы будете готовы. Однако обратите внимание, что смешивание пакетов не работает в рамках одной отдельной функции.
Мы рекомендуем переносить функции по одной, а затем тестировать и проверять их.
Как проверить версии CLI Firebase и firebase-functions
Убедитесь, что вы используете версию Firebase CLI 12.00 и версию firebase-functions 4.3.0 или более поздние. Более новые версии будут поддерживать как устройства первого, так и второго поколения.
Как обновить импорт
Функции второго поколения импортируются из подпакета v2 в firebase-functionsSDK. Этот путь импорта – все, что нужно Firebase CLI, чтобы определить, следует ли развертывать код функции как функцию первого или второго поколения.
Подпакет v2 является модульным, поэтому мы рекомендуем импортировать только нужный вам модуль.
Предыдущая версия: первое поколение
const functions = require("firebase-functions/v1");
После: второе поколение
// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
Как обновить определения триггеров
Поскольку SDK второго поколения поддерживает модульные импорты, обновите определения триггеров, чтобы они отражали изменения, внесенные на предыдущем шаге.
Аргументы, передаваемые в функции обратного вызова для некоторых триггеров, изменились. В этом примере обратите внимание, что аргументы обратного вызова onDocumentCreated объединены в один объект event. Кроме того, у некоторых триггеров появились новые удобные функции конфигурации, например параметр cors триггера onRequest.
Предыдущая версия: первое поколение
const functions = require("firebase-functions/v1");
exports.date = functions.https.onRequest((req, res) => {
// ...
});
exports.uppercase = functions.firestore
.document("my-collection/{docId}")
.onCreate((change, context) => {
// ...
});
После: второе поколение
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 для извлечения этих свойств непосредственно в сигнатуре обработчика, что сводит к минимуму необходимость переписывать логику функции.
Справочник по сопоставлению поставщиков
| Поставщик | Аргументы первого поколения | 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 }) => { ... }
|
Первое поколение
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
const data = message.json;
const eventId = context.eventId;
// ... rest of the logic
});
Новый альтернативный вариант (второе поколение с деструктуризацией):
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 блокирует развертывание, если не все параметры имеют допустимое значение. Это гарантирует, что функция не будет развернута без необходимой конфигурации.
Предыдущая версия: первое поколение
const functions = require("firebase-functions/v1");
exports.getQuote = functions.https.onRequest(async (req, res) => {
const quote = await fetchMotivationalQuote(functions.config().apiKey);
// ...
});
После: второе поколение
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, перенесите ее при переходе на второе поколение.
Поддержка functions.config API прекратится в марте 2027 г.
После этой даты развертывания с использованием functions.config будут завершаться с ошибкой.
Чтобы избежать сбоев при развертывании, перенесите конфигурацию в Cloud Secret Manager с помощью интерфейса командной строки Firebase. Мы настоятельно рекомендуем использовать этот способ, так как он наиболее эффективен и безопасен.
Экспорт конфигурации с помощью интерфейса командной строки Firebase
Чтобы экспортировать существующую конфигурацию среды в новый секрет в Cloud Secret Manager, используйте команду
config export:$ 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>
Как задать настройки среды выполнения
Настройка параметров выполнения изменилась в устройствах первого и второго поколений. В устройствах второго поколения также появилась возможность задавать параметры для всех функций.
Предыдущая версия: первое поколение
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) => {
// ...
});
После: второе поколение
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 (для устройств первого поколения), так и для сервисного аккаунта по умолчанию Compute Engine (для устройств второго поколения).
Как использовать параллелизм
Важное преимущество функций второго поколения – возможность одного экземпляра функции обрабатывать несколько запросов одновременно. Это может значительно сократить количество холодных запусков, с которыми сталкиваются конечные пользователи. По умолчанию параллелизм установлен на 80, но вы можете задать любое значение от 1 до 1000:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// set concurrency value
concurrency: 500
},
(req, res) => {
// ...
});
Настройка параллелизма может повысить производительность и снизить стоимость функций. Подробнее о параллельных запросах можно узнать в разделе Разрешить параллельные запросы.
Как проверить использование глобальных переменных
Функции первого поколения, написанные без учета параллельного выполнения, могут использовать глобальные переменные, которые задаются и считываются при каждом запросе. Если включить параллельное выполнение и один экземпляр начнет обрабатывать несколько запросов одновременно, в функции могут появиться ошибки, поскольку параллельные запросы будут одновременно устанавливать и считывать глобальные переменные.
При обновлении можно задать для функции значение gcf_gen1 для параметра CPU и значение 1 для параметра concurrency, чтобы восстановить поведение первого поколения:
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
firebase functions:deleteинтерфейса командной строки.
Как перенести триггеры фона
Фоновые триггеры (например, 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 ... });Разверните это изменение.
Удалите из кода определение функции первого поколения и повторно разверните его. Интерфейс командной строки предложит удалить функцию первого поколения из Google Cloud.