Atualize as funções do Node.js de 1ª geração para a 2ª geração

Os aplicativos que atualmente usam funções de 1ª geração devem considerar a migração para a 2ª geração seguindo as instruções deste guia. As funções de segunda geração usam o Cloud Run para fornecer melhor desempenho, melhor configuração, melhor monitoramento e muito mais.

Os exemplos nesta página pressupõem que você esteja usando JavaScript com módulos CommonJS ( require importações de estilo), mas os mesmos princípios se aplicam a JavaScript com ESM ( import … from importações de estilo) e TypeScript.

O processo de migração

As funções de 1ª e 2ª geração podem coexistir lado a lado no mesmo arquivo. Isso permite uma migração fácil, peça por peça, quando estiver pronto. Recomendamos migrar uma função por vez, realizando testes e verificações antes de continuar.

Verifique as versões do Firebase CLI e firebase-function

Certifique-se de usar pelo menos Firebase CLI versão 12.00 e firebase-functions versão 4.3.0 . Qualquer versão mais recente suportará a 2ª geração e também a 1ª geração.

Atualizar importações

As funções de 2ª geração são importadas do subpacote v2 no firebase-functions SDK. Esse caminho de importação diferente é tudo o que a CLI do Firebase precisa para determinar se deve implantar seu código de função como uma função de primeira ou segunda geração.

O subpacote v2 é modular e recomendamos importar apenas o módulo específico necessário.

Antes: 1ª geração

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

Depois: 2ª geração

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

Atualizar definições de gatilho

Como o SDK de 2ª geração favorece importações modulares, atualize as definições do gatilho para refletir as importações alteradas da etapa anterior.

Os argumentos passados ​​para retornos de chamada de alguns gatilhos foram alterados. Neste exemplo, observe que os argumentos para o retorno de chamada onDocumentCreated foram consolidados em um único objeto event . Além disso, alguns gatilhos possuem novos recursos de configuração convenientes, como a opção cors do gatilho onRequest .

Antes: 1ª geração

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

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

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

Depois: 2ª geração

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 configuração parametrizada

As funções de 2ª geração abandonam o suporte para functions.config em favor de uma interface mais segura para definir parâmetros de configuração declarativamente dentro de sua base de código. Com o novo módulo params , a CLI bloqueia a implantação, a menos que todos os parâmetros tenham um valor válido, garantindo que uma função não seja implantada com configuração ausente.

Migrar para o subpacote params

Se você estiver usando a configuração de ambiente com functions.config , poderá migrar sua configuração existente para a configuração parametrizada .

Antes: 1ª geração

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

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

  // ...
});

Depois: 2ª geração

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

  // ...
});

Definir valores de parâmetros

Na primeira vez que você implanta, a CLI do Firebase solicita todos os valores dos parâmetros e salva os valores em um arquivo dotenv. Para exportar seus valores de functions.config, execute firebase functions:config:export .

Para segurança adicional, você também pode especificar tipos de parâmetros e regras de validação .

Caso especial: chaves de API

O módulo params integra-se ao Cloud Secret Manager, que fornece controle de acesso refinado a valores confidenciais, como chaves de API. Consulte parâmetros secretos para obter mais informações.

Antes: 1ª geração

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

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

Depois: 2ª geração

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

Definir opções de tempo de execução

A configuração das opções de tempo de execução mudou entre a 1ª e a 2ª geração. A 2ª geração também adiciona um novo recurso para definir opções para todas as funções.

Antes: 1ª geração

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

Depois: 2ª geração

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 simultaneidade

Uma vantagem significativa das funções de 2ª geração é a capacidade de uma única instância de função atender mais de uma solicitação ao mesmo tempo. Isso pode reduzir drasticamente o número de partidas a frio experimentadas pelos usuários finais. Por padrão, a simultaneidade é definida como 80, mas você pode defini-la como qualquer valor de 1 a 1000:

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

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

O ajuste da simultaneidade pode melhorar o desempenho e reduzir o custo das funções. Saiba mais sobre simultaneidade em Permitir solicitações simultâneas .

Auditar o uso de variáveis ​​globais

Funções de 1ª geração escritas sem simultaneidade em mente podem usar variáveis ​​globais que são definidas e lidas em cada solicitação. Quando a simultaneidade está habilitada e uma única instância começa a lidar com várias solicitações ao mesmo tempo, isso pode introduzir bugs em sua função, pois as solicitações simultâneas começam a configurar e ler variáveis ​​globais simultaneamente.

Durante a atualização, você pode definir a CPU da sua função como gcf_gen1 e definir concurrency como 1 para restaurar o comportamento da 1ª geração:

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

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

No entanto, isto não é recomendado como uma solução a longo prazo, pois perde as vantagens de desempenho das funções de 2ª geração. Em vez disso, audite o uso de variáveis ​​globais em suas funções e remova essas configurações temporárias quando estiver pronto.

Migre o tráfego para as novas funções de 2ª geração

Assim como ao alterar a região ou o tipo de gatilho de uma função , você precisará dar um novo nome à função de 2ª geração e migrar lentamente o tráfego para ela.

Não é possível atualizar uma função de 1ª para 2ª geração com o mesmo nome e executar firebase deploy . Fazer isso resultará no erro:

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 essas etapas, primeiro certifique-se de que sua função seja idempotente , pois tanto a nova versão quanto a versão antiga de sua função estarão em execução ao mesmo tempo durante a alteração. Por exemplo, se você tiver uma função de 1ª geração que responde a eventos de gravação no Firestore, certifique-se de que responder a uma gravação duas vezes, uma vez pela função de 1ª geração e uma vez pela função de 2ª geração, em resposta a esses eventos deixe seu aplicativo em um estado de alerta. estado consistente.

  1. Renomeie a função no seu código de funções. Por exemplo, renomeie resizeImage para resizeImageSecondGen .
  2. Implante a função, de modo que tanto a função original de 1ª geração quanto a função de 2ª geração estejam em execução.
    1. No caso de gatilhos chamáveis, fila de tarefas e HTTP, comece a apontar todos os clientes para a função de 2ª geração atualizando o código do cliente com o nome ou URL da função de 2ª geração.
    2. Com acionadores em segundo plano, as funções de 1ª e 2ª geração responderão a todos os eventos imediatamente após a implantação.
  3. Quando todo o tráfego for migrado, exclua a função de 1ª geração usando o comando firebase functions:delete da CLI do Firebase.
    1. Opcionalmente, renomeie a função de 2ª geração para corresponder ao nome da função de 1ª geração.