Administra funciones


Usa los comandos de Firebase CLI o configura opciones de entorno de ejecución en el código fuente para implementar, borrar y modificar funciones.

Implementa funciones

Para implementar funciones, ejecuta el siguiente comando de Firebase CLI:

firebase deploy --only functions

De forma predeterminada, Firebase CLI implementa todas las funciones dentro de la fuente al mismo tiempo. Si tu proyecto contiene más de 5 funciones, te recomendamos que uses la marca --only con nombres de funciones específicas para implementar solo las funciones que editaste. Si implementas funciones específicas de esta forma, acelerarás el proceso de implementación y evitarás alcanzar los límites de las cuotas de implementación. Por ejemplo:

firebase deploy --only functions:addMessage,functions:makeUppercase

Cuando implementas una gran cantidad de funciones, es posible que excedas la cuota estándar y recibas mensajes de error HTTP 429 o 500. Para solucionar este problema, implementa funciones en grupos de 10 o menos.

Para ver una lista completa de los comandos disponibles, consulta la Referencia de Firebase CLI.

Según la configuración predeterminada, Firebase CLI busca el código fuente en la carpeta functions/. Si lo prefieres, puedes organizar funciones en bases de código o varios conjuntos de archivos.

Borra funciones

Puedes borrar las funciones implementadas previamente de estas maneras:

  • De forma explícita en Firebase CLI con functions:delete
  • De forma explícita en la consola de Google Cloud.
  • De forma implícita si quitas la función de la fuente antes de la implementación.

Para realizar cualquiera de estas operaciones, deberás confirmar que quieres quitar la función de producción.

La función de eliminación explícita en Firebase CLI admite varios argumentos y grupos de funciones, y te permite especificar que una función se ejecute en una región en particular. Además, puedes anular la solicitud de confirmación.

# Delete all functions that match the specified name in all regions.
firebase functions:delete myFunction
# Delete a specified function running in a specific region.
firebase functions:delete myFunction --region us-east-1
# Delete more than one function
firebase functions:delete myFunction myOtherFunction
# Delete a specified functions group.
firebase functions:delete groupA
# Bypass the confirmation prompt.
firebase functions:delete myFunction --force

En la función de eliminación implícita, firebase deploy analiza la fuente y quita de producción las funciones eliminadas del archivo.

Modifica el nombre, la región o el activador de una función

Si quieres cambiar el nombre, las regiones o el activador de una función que maneja tráfico de producción, sigue los pasos de esta sección para no perder eventos durante la modificación. Antes de hacerlo, asegúrate de que tu función sea idempotente, ya que se ejecutarán al mismo tiempo la versión nueva y la antigua de la función durante el cambio.

Cambia el nombre de una función

Para cambiar el nombre de una función, crea una versión nueva de la función con otro nombre en la fuente y, luego, ejecuta dos comandos de implementación separados. El primer comando implementa la función nueva con otro nombre y el segundo comando quita la versión implementada anteriormente. Por ejemplo, si tienes una función de Node.js llamada webhook que te gustaría cambiar a webhookNew, modifica el código de la siguiente manera:

// before
const functions = require('firebase-functions');

exports.webhook = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

// after
const functions = require('firebase-functions');

exports.webhookNew = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

A continuación, ejecuta los siguientes comandos para implementar la función nueva:

# Deploy new function called webhookNew
firebase deploy --only functions:webhookNew

# Wait until deployment is done; now both webhookNew and webhook are running

# Delete webhook
firebase functions:delete webhook

Cambia las regiones de una función

Si cambias las regiones determinadas de una función que maneja tráfico de producción, puedes perder eventos. Para evitarlo, realiza los siguientes pasos en el mismo orden:

  1. Cambia el nombre de la función y sus regiones como desees.
  2. Implementa la función con el nombre nuevo. Esto ejecutará temporalmente el mismo código en ambos conjuntos de regiones.
  3. Borra la función anterior.

Por ejemplo, si tienes una función llamada webhook que se encuentra actualmente en la región de funciones predeterminada de us-central1 y deseas migrarla a asia-northeast1, primero debes modificar tu código fuente para cambiarle el nombre a la función y revisar la región.

// before
const functions = require('firebase-functions');

exports.webhook = functions
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

// after
const functions = require('firebase-functions');

exports.webhookAsia = functions
    .region('asia-northeast1')
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

A continuación, impleméntala con el comando:

firebase deploy --only functions:webhookAsia

Ahora, tienes dos funciones idénticas en ejecución: webhook se ejecuta en us-central1 y webhookAsia se ejecuta en asia-northeast1.

Luego, borra webhook:

firebase functions:delete webhook

Solamente queda una función, webhookAsia, que se ejecuta en asia-northeast1.

Cambia el tipo de activador de una función

A medida que desarrollas tu implementación de Cloud Functions para Firebase, es posible que debas cambiar el tipo de activador de una función por diversas razones. Por ejemplo, es posible que quieras cambiar de un tipo de evento de Firebase Realtime Database o Cloud Firestore a otro.

No es posible cambiar el tipo de evento de una función solo con cambiar el código fuente y ejecutar firebase deploy. Para evitar errores, usa el siguiente procedimiento a fin de cambiar el tipo de activador de una función:

  1. Modifica el código fuente para que incluya una función nueva con el tipo de activador que desees.
  2. Implementa la función, lo que tendrá como resultado la ejecución temporal de la función antigua y de la nueva.
  3. Borra de producción la función antigua de forma explícita con Firebase CLI.

Por ejemplo, si tienes una función de Node.js llamada objectChanged con un tipo de evento heredado onChange y deseas cambiarlo a onFinalize, primero debes cambiar el nombre de la función y modificarla para que tenga el tipo de evento onFinalize.

// before
const functions = require('firebase-functions');

exports.objectChanged = functions.storage.object().onChange((object) => {
    return console.log('File name is: ', object.name);
});

// after
const functions = require('firebase-functions');

exports.objectFinalized = functions.storage.object().onFinalize((object) => {
    return console.log('File name is: ', object.name);
});

A continuación, y antes de borrar la función antigua, ejecuta los siguientes comandos para crear primero la función nueva:

# Create new function objectFinalized
firebase deploy --only functions:objectFinalized

# Wait until deployment is done; now both objectChanged and objectFinalized are running

# Delete objectChanged
firebase functions:delete objectChanged

Configura las opciones de ejecución

Cloud Functions para Firebase te permite seleccionar opciones de ejecución, como la versión del entorno de ejecución de Node.js, el tiempo de espera por función, la asignación de memoria y la cantidad mínima o máxima de instancias de función.

Como práctica recomendada, estas opciones (excepto la versión de Node.js) deben establecerse en un objeto de configuración dentro del código de la función. Este objeto RuntimeOptions es la fuente de información para las opciones del entorno de ejecución de tu función y anulará las opciones establecidas mediante cualquier otro método (como la consola de Google Cloud o la CLI de gcloud).

Si tu flujo de trabajo de desarrollo implica configurar manualmente las opciones del entorno de ejecución a través de la consola de Google Cloud o la CLI de gcloud, y no quieres que se anulen estos valores en cada implementación, configura la opción preserveExternalChanges como true. Cuando esta opción se configura como true, Firebase combina las opciones del entorno de ejecución configuradas en el código con la configuración de la versión implementada actualmente de la función y la siguiente prioridad:

  1. Si la opción está establecida en el código de las funciones, se anulan los cambios externos.
  2. Si la opción está establecida en RESET_VALUE en el código de las funciones, se anulan los cambios externos con el valor predeterminado.
  3. Si la opción no está configurada en el código de las funciones, pero sí en la función implementada actualmente, se usa la opción especificada en la función implementada.

No se recomienda usar la opción preserveExternalChanges: true en la mayoría de los casos porque el código ya no será la fuente de confianza completa de las opciones del entorno de ejecución para las funciones. Si la usas, consulta la consola de Google Cloud o usa la CLI de gcloud para ver la configuración completa de una función.

Configura la versión de Node.js

El SDK de Firebase para Cloud Functions permite seleccionar el entorno de ejecución de Node.js. Puedes ejecutar todas las funciones de un proyecto de manera exclusiva en el entorno correspondiente a una de estas versiones compatibles de Node.js:

  • Node.js 20 (vista previa)
  • Node.js 18
  • Node.js 16
  • Node.js 14

Sigue estos pasos para configurar la versión de Node.js:

Puedes configurar la versión en el campo engines del archivo package.json que se creó en el directorio functions/ durante la inicialización. Por ejemplo, edita la línea que está a continuación en package.json si quieres usar solo la versión 18:

  "engines": {"node": "18"}

Si usas el administrador de paquetes Yarn o tienes otros requisitos específicos para el campo engines, puedes configurar el entorno de ejecución del SDK de Firebase para Cloud Functions en firebase.json en su lugar:

  {
    "functions": {
      "runtime": "nodejs18" // or nodejs14, nodejs16 or nodejs20
    }
  }

La CLI usa el valor establecido en firebase.json antes que cualquier valor o rango que configures por separado en package.json.

Actualiza el entorno de ejecución de Node.js

Sigue estos pasos para actualizar el entorno de ejecución de Node.js:

  1. Asegúrate de que tu proyecto tenga el plan de precios Blaze.
  2. Asegúrate de usar la versión 11.18.0 o posterior de Firebase CLI.
  3. Cambia el valor de engines en el archivo package.json que se creó en el directorio functions/ durante la inicialización. Por ejemplo, si actualizas de la versión 16 a la 18, la entrada debería tener este aspecto: "engines": {"node": "18"}.
  4. También puedes probar los cambios con Firebase Local Emulator Suite.
  5. Vuelve a implementar todas las funciones.

Configura la versión de Python

El SDK de Firebase para Cloud Functions versión 12.0.0 y posteriores permite seleccionar el entorno de ejecución de Python (para la funcionalidad de versión preliminar pública). Configura la versión del entorno de ejecución en firebase.json como se muestra a continuación:

  {
    "functions": {
      "runtime": "python310" // or python311
    }
  }

Controla el comportamiento del escalamiento

Según la configuración predeterminada, Cloud Functions para Firebase escala la cantidad de instancias en ejecución según la cantidad de solicitudes entrantes y podría reducir la escala verticalmente a cero en los momentos con menos tráfico. Sin embargo, si tu app requiere una latencia reducida y deseas limitar la cantidad de inicios en frío, puedes cambiar este comportamiento predeterminado si especificas una cantidad mínima de instancias de contenedor que se deben mantener en espera y listas para entregar solicitudes.

De manera similar, puedes establecer una cantidad máxima para limitar el escalamiento de las instancias en respuesta a las solicitudes entrantes. Usa este parámetro de configuración como una forma de controlar tus costos o limitar la cantidad de conexiones a un servicio de respaldo, como una base de datos.

Si usas esta configuración junto con el parámetro de configuración de simultaneidad por instancia (nuevo en la versión de 2ª gen.), puedes controlar y ajustar el comportamiento de escalamiento de tus funciones. La naturaleza de tu aplicación y función determinará qué configuración es la más rentable y generará el mejor rendimiento.

Para algunas apps con poco tráfico, la opción de CPU más baja sin simultaneidad es óptima. Para otras en las que los inicios en frío son un problema crítico, configurar una simultaneidad alta, así como instancias mínimas, implica que un conjunto de instancias se mantenga siempre en espera para manejar grandes aumentos de tráfico.

En el caso de las apps de menor escala que reciben muy poco tráfico, configurar instancias máximas bajas con alta simultaneidad supone que la app puede manejar aumentos repentinos de tráfico sin incurrir en costos excesivos. Sin embargo, ten en cuenta que cuando la cantidad máxima de instancias se establece en un valor demasiado bajo, es posible que las solicitudes se descarten cuando se alcance ese límite.

Permite solicitudes simultáneas

En Cloud Functions para Firebase (1ª gen.), cada instancia podía procesar una solicitud a la vez, por lo que el comportamiento del escalamiento se establecía solo con los parámetros de configuración mínimos y máximos para la cantidad de instancias. Además de controlar la cantidad de instancias, en Cloud Functions para Firebase (2ª gen.) puedes manejar la cantidad de solicitudes que cada instancia puede entregar al mismo tiempo con la opción concurrency. El valor predeterminado para la simultaneidad es 80, pero es posible configurarlo en cualquier número entero entre 1 y 1,000.

Las funciones con parámetros de configuración de simultaneidad más altos pueden absorber los aumentos repentinos del tráfico sin iniciar en frío, ya que cada instancia puede tener cierto margen. Si una instancia está configurada para manejar hasta 50 solicitudes simultáneas, pero actualmente controla solo 25, puede manejar un aumento de 25 solicitudes adicionales sin requerir que se inicie una nueva instancia en frío. Por el contrario, si se aplicó una configuración de simultaneidad de solo 1, ese aumento repentino en las solicitudes podría generar 25 inicios en frío.

En esta situación simplificada, se muestran las posibles mejoras de eficiencia de la simultaneidad. En realidad, el comportamiento del escalamiento para optimizar la eficiencia y reducir los inicios en frío con simultaneidad es más complejo. La simultaneidad en Cloud Functions para Firebase (2ª gen.) usa la tecnología de Cloud Run y sigue las reglas de Cloud Run del ajuste de escala automático de instancias de contenedores.

Cuando experimentes con una configuración de simultaneidad más alta en Cloud Functions para Firebase (2ª gen.), ten en cuenta lo siguiente:

  • Si se ajusta la simultaneidad con un valor más alto, posiblemente se requieran más CPU y RAM para obtener un rendimiento óptimo hasta alcanzar un límite práctico. Por ejemplo, es posible que una función que procese muchos videos o imágenes no cuente con los recursos necesarios para procesar 1,000 solicitudes simultáneas, incluso cuando se maximice la configuración de CPU y RAM.
  • Dado que Cloud Functions para Firebase (2ª gen.) usa la tecnología de Cloud Run, también puedes consultar la guía de Google Cloud para optimizar la simultaneidad.
  • Asegúrate de probar de forma exhaustiva la simultaneidad en un entorno de pruebas antes de cambiar a la simultaneidad en producción.

Mantén una cantidad mínima de instancias en espera

Puedes establecer una cantidad mínima de instancias para una función en el código fuente. Por ejemplo, la siguiente función establece un mínimo de 5 instancias para mantenerse en espera:

Node.js

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

exports.getAutocompleteResponse = onCall(
  {
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  },
  (event) => {
    // Autocomplete user’s search term
  }
);

Python (vista previa)

@https_fn.on_call(min_instances=5)
def get_autocomplete_response(event: https_fn.CallableRequest) -> https_fn.Response:

A continuación, se mencionan algunos aspectos que deberás tener en cuenta cuando configures un valor mínimo de instancias:

  • Si Cloud Functions para Firebase escala tu app por sobre el parámetro de configuración, experimentarás un inicio en frío en cada instancia que supere ese umbral.
  • Los inicios en frío afectan de forma más grave a las apps con aumento de tráfico. Si tu app tiene un aumento de tráfico y estableces un valor lo suficientemente alto como para que los inicios en frío se reduzcan en cada aumento de tráfico, verás una disminución significativa de la latencia. En el caso de las apps con tráfico constante, es poco probable que los inicios en frío afecten al rendimiento de forma considerable.
  • Configurar instancias mínimas puede ser útil para los entornos de producción, pero, por lo general, se debe evitar en entornos de pruebas. Para reducir la escala a cero en tu proyecto de prueba y seguir disminuyendo los inicios en frío en el proyecto de producción, puedes establecer un valor de instancias mínimo en la configuración parametrizada:

    Node.js

    const functions = require('firebase-functions');
    const { defineInt, defineString } = require('firebase-functions/params');
    
    // Define some parameters
    const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
    const welcomeMessage = defineString('WELCOME_MESSAGE');
    
    // To use configured parameters inside the config for a function, provide them 
    // directly. To use them at runtime, call .value() on them.
    export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
      (req, res) => {
        res.send(`${welcomeMessage.value()}! I am a function.`);
      }
    );
    

    Python (vista previa)

    MIN_INSTANCES = params.IntParam("HELLO_WORLD_MININSTANCES")
    WELCOME_MESSAGE = params.StringParam("WELCOME_MESSAGE")
    
    @https_fn.on_request(min_instances=MIN_INSTANCES.value())
    def get_autocomplete_response(event: https_fn.Request) -> https_fn.Response:
        return https_fn.Response(f"{WELCOME_MESSAGE.value()} I'm a function.")
    

Limita la cantidad máxima de instancias para una función

Puedes establecer un valor para la cantidad máxima de instancias en el código fuente de la función. Por ejemplo, esta función establece un límite de 100 instancias para no sobrecargar una base de datos heredada hipotética, de la siguiente manera:

Node.js

const { onMessagePublished } = require("firebase-functions/v2/pubsub");

exports.mirrorevents = onMessagePublished(
  { topic: "topic-name", maxInstances: 100 },
  (event) => {
    // Connect to legacy database
  }
);

Python (vista previa)

@pubsub_fn.on_message_published(topic="topic-name", max_instances=100)
def mirrorevents(event: pubsub_fn.CloudEvent):
#  Connect to legacy database

Si una función de HTTP escala verticalmente hasta el límite máximo de instancias, las solicitudes nuevas se ponen en cola durante 30 segundos y, luego, se rechazan con un código de respuesta de 429 Too Many Requests si no hay una instancia disponible para ese momento.

Si quieres obtener más información, consulta estas prácticas recomendadas para establecer la cantidad máxima de instancias.

Configura el tiempo de espera y la asignación de memoria

En algunos casos, es posible que tus funciones necesiten requisitos especiales para tener un valor de tiempo de espera largo o una mayor asignación de memoria. Puedes establecer estos valores en la consola de Google Cloud o en el código fuente de la función (solamente en Firebase).

Si quieres establecer la asignación de memoria y el tiempo de espera en el código fuente de las funciones, usa las opciones globales de memoria y el tiempo de espera en segundos, y así podrás personalizar la máquina virtual que ejecuta tus funciones. Por ejemplo, la siguiente función de Cloud Storage usa 1 GiB de memoria y su tiempo de espera se agota después de 300 segundos:

Node.js

exports.convertLargeFile = onObjectFinalized({
  timeoutSeconds: 300,
  memory: "1GiB",
}, (event) => {
  // Do some complicated things that take a lot of memory and time
});

Python (vista previa)

@storage_fn.on_object_finalized(timeout_sec=300, memory=options.MemoryOption.GB_1)
def convert_large_file(event: storage_fn.CloudEvent):
# Do some complicated things that take a lot of memory and time.

El valor máximo del tiempo de espera en segundos es de 540 o 9 minutos.

Si quieres configurar el tiempo de espera y la asignación de memoria en la consola de Google Cloud, sigue estos pasos:

  1. En la consola de Google Cloud, selecciona Cloud Functions para Firebase en el menú de la izquierda.
  2. Haz clic en el nombre de una Function para elegirla en la lista de funciones.
  3. Haz clic en el ícono Editar en el menú de la parte superior.
  4. Selecciona una asignación de memoria del menú desplegable Memoria asignada.
  5. Haz clic en Más para ver las opciones avanzadas y, a continuación, ingresa la cantidad de segundos en el cuadro de texto Tiempo de espera.
  6. Haz clic en Guardar para actualizar la Function.

Anula los valores predeterminados de la CPU

Con hasta 2 GB de memoria asignada, cada función de Cloud Functions para Firebase (2ª gen.) tiene como valor predeterminado una CPU y, luego, aumenta a 2 CPU para 4 y 8 GB. Ten en cuenta que este comportamiento es significativamente diferente al comportamiento predeterminado de la 1ª gen. en aspectos que podrían generar costos un poco más altos para las funciones de memoria insuficiente, como se indica en la siguiente tabla:

RAM asignada CPU predeterminada de la versión 1 (fraccionaria) CPU predeterminada de la versión 2 Aumento de precios por ms
128 MB 1/12 1 10.5x
256 MB 1/6 1 5.3x
512 MB 1/3 1 2.7x
1 GB 7/12 1 1.6x
2 GB 1 1 1x
4 GB 2 2 1x
8 GB 2 2 1x
16 GB No disponible 4 No disponible

Si prefieres el comportamiento de la 1ª gen. para las funciones de la 2ª gen., establece los valores predeterminados de la primera generación como una opción global:

Node.js

// Turn off Firebase defaults
setGlobalOptions({ cpu: 'gcf_gen1' });

Python (vista previa)

# Use 1st gen behavior
set_global_options(cpu="gcf_gen1")

En el caso de las funciones que requieren mucha CPU, la 2ª gen. proporciona la flexibilidad necesaria para configurar CPU adicionales. Además, puedes optimizar la CPU por función, como se muestra a continuación:

Node.js

// Boost CPU in a function:
export const analyzeImage = onObjectFinalized({ cpu: 2 }, (event) => {
  // computer vision goes here
});

Python (vista previa)

# Boost CPU in a function:
@storage_fn.on_object_finalized(cpu=2)
def analyze_image(event: storage_fn.CloudEvent):
# computer vision goes here