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.