Actualice las funciones de Node.js de 1.ª generación a 2.ª generación

Las aplicaciones que actualmente utilizan funciones de 1.ª generación deberían considerar migrar a la 2.ª generación siguiendo las instrucciones de esta guía. Las funciones de segunda generación utilizan Cloud Run para proporcionar un mejor rendimiento, una mejor configuración, una mejor supervisión y más.

Los ejemplos de esta página suponen que está utilizando JavaScript con módulos CommonJS ( require importaciones de estilos), pero los mismos principios se aplican a JavaScript con ESM ( import … from importaciones de estilos) y TypeScript.

El proceso migratorio

Las funciones de 1.ª y 2.ª generación pueden coexistir una al lado de la otra en el mismo archivo. Esto permite una fácil migración pieza por pieza, a medida que esté listo. Recomendamos migrar una función a la vez, realizar pruebas y verificaciones antes de continuar.

Verifique las versiones de Firebase CLI y firebase-function

Asegúrate de utilizar al menos la versión 12.00 de Firebase CLI y la versión 4.3.0 de firebase-functions . Cualquier versión más nueva admitirá tanto la 2.ª generación como la 1.ª generación.

Actualizar importaciones

Las funciones de segunda generación se importan desde el subpaquete v2 en el SDK firebase-functions . Esta ruta de importación diferente es todo lo que Firebase CLI necesita para determinar si implementar su código de función como una función de primera o segunda generación.

El subpaquete v2 es modular y recomendamos importar solo el módulo específico que necesite.

Antes: 1.ª generación

const functions = require("firebase-functions");

Después: 2da generación

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

Actualizar definiciones de desencadenadores

Dado que el SDK de segunda generación favorece las importaciones modulares, actualice las definiciones de los activadores para reflejar las importaciones modificadas del paso anterior.

Los argumentos pasados ​​a las devoluciones de llamada para algunos desencadenantes han cambiado. En este ejemplo, tenga en cuenta que los argumentos de la devolución de llamada onDocumentCreated se han consolidado en un único objeto event . Además, algunos disparadores tienen nuevas características de configuración convenientes, como la opción cors del disparador onRequest .

Antes: 1.ª generación

const functions = require("firebase-functions");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

Después: 2da generación

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) => {
  /* ... */
});

Usar configuración parametrizada

Las funciones de segunda generación eliminan el soporte para functions.config en favor de una interfaz más segura para definir parámetros de configuración de forma declarativa dentro de su código base. Con el nuevo módulo params , la CLI bloquea la implementación a menos que todos los parámetros tengan un valor válido, lo que garantiza que no se implemente una función sin configuración.

Migrar al subpaquete params

Si ha estado utilizando la configuración del entorno con functions.config , puede migrar su configuración existente a una configuración parametrizada .

Antes: 1.ª generación

const functions = require("firebase-functions");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

Después: 2da generación

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());

  // ...
});

Establecer valores de parámetros

La primera vez que realiza la implementación, Firebase CLI solicita todos los valores de los parámetros y los guarda en un archivo dotenv. Para exportar sus valores de funciones.config, ejecute firebase functions:config:export .

Para mayor seguridad, también puede especificar tipos de parámetros y reglas de validación .

Caso especial: claves API

El módulo params se integra con Cloud Secret Manager, que proporciona un control de acceso detallado a valores confidenciales como claves API. Consulte los parámetros secretos para obtener más información.

Antes: 1.ª generación

const functions = require("firebase-functions");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});

Después: 2da generación

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());
    // ...
  }
);

Establecer opciones de tiempo de ejecución

La configuración de las opciones de tiempo de ejecución ha cambiado entre la 1.ª y la 2.ª generación. La segunda generación también agrega una nueva capacidad para configurar opciones para todas las funciones.

Antes: 1.ª generación

const functions = require("firebase-functions");

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) => {
    // ...
  });

Después: 2da generación

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) => {
  /* ... */
});

Usar concurrencia

Una ventaja significativa de las funciones de segunda generación es la capacidad de una única instancia de función para atender más de una solicitud a la vez. Esto puede reducir drásticamente la cantidad de arranques en frío que experimentan los usuarios finales. De forma predeterminada, la simultaneidad está establecida en 80, pero puede establecerla en cualquier valor entre 1 y 1000:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

El ajuste de la concurrencia puede mejorar el rendimiento y reducir el costo de las funciones. Obtenga más información sobre la simultaneidad en Permitir solicitudes simultáneas .

Auditar el uso de variables globales

Las funciones de primera generación escritas sin tener en cuenta la simultaneidad pueden utilizar variables globales que se configuran y leen en cada solicitud. Cuando la simultaneidad está habilitada y una sola instancia comienza a manejar múltiples solicitudes a la vez, esto puede introducir errores en su función ya que las solicitudes simultáneas comienzan a configurar y leer variables globales simultáneamente.

Mientras actualiza, puede configurar la CPU de su función en gcf_gen1 y establecer concurrency en 1 para restaurar el comportamiento de primera generación:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});

Sin embargo, esto no se recomienda como solución a largo plazo, ya que pierde las ventajas de rendimiento de las funciones de segunda generación. En su lugar, audite el uso de variables globales en sus funciones y elimine estas configuraciones temporales cuando esté listo.

Migrar el tráfico a las nuevas funciones de segunda generación

Al igual que cuando se cambia la región o el tipo de activador de una función , deberá darle un nuevo nombre a la función de segunda generación y migrar lentamente el tráfico hacia ella.

No es posible actualizar una función de 1.ª a 2.ª generación con el mismo nombre y ejecutar firebase deploy . Al hacerlo, se producirá el error:

Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

Antes de seguir estos pasos, primero asegúrese de que su función sea idempotente , ya que tanto la versión nueva como la versión anterior de su función se ejecutarán al mismo tiempo durante el cambio. Por ejemplo, si tiene una función de 1.ª generación que responde a eventos de escritura en Firestore, asegúrese de que responder a una escritura dos veces, una vez por la función de 1.ª generación y otra por la función de 2.ª generación, en respuesta a esos eventos deje su aplicación en un estado consistente.

  1. Cambie el nombre de la función en su código de funciones. Por ejemplo, cambie el nombre resizeImage a resizeImageSecondGen .
  2. Implemente la función de modo que se estén ejecutando tanto la función original de 1.ª generación como la función de 2.ª generación.
    1. En el caso de activadores invocables, de cola de tareas y HTTP, comience a señalar a todos los clientes a la función de segunda generación actualizando el código del cliente con el nombre o la URL de la función de segunda generación.
    2. Con activadores en segundo plano, las funciones de 1.ª y 2.ª generación responderán a cada evento inmediatamente después de la implementación.
  3. Cuando se haya migrado todo el tráfico, elimine la función de 1.ª generación mediante el comando firebase functions:delete Firebase CLI.
    1. Opcionalmente, cambie el nombre de la función de 2.ª generación para que coincida con el nombre de la función de 1.ª generación.