Gerenciar funções


Você pode implantar, excluir e modificar funções usando os comandos da CLI do Firebase ou definindo opções de ambiente de execução no código-fonte das suas funções.

Implantar funções

Para implantar funções, execute o seguinte comando da CLI do Firebase:

firebase deploy --only functions

Por padrão, a CLI do Firebase implanta todas as funções dentro da origem ao mesmo tempo. Se o projeto tiver mais de cinco funções, recomendamos que você use a sinalização --only com nomes de função específicos para implantar apenas as funções editadas. Implantar funções específicas dessa forma acelera o procedimento e ajuda a evitar alcançar o limite de cotas de implantação. Por exemplo:

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

Ao implantar um grande número de funções, talvez você exceda a cota padrão e receba mensagens de erro HTTP 429 ou 500. Para resolver esse problema, implante funções em grupos de 10 ou menos.

Consulte a referência da CLI do Firebase para conferir a lista completa de comandos disponíveis.

Por padrão, a CLI do Firebase procura o código-fonte na pasta functions/. Se preferir, organize funções em bases de código ou em vários conjuntos de arquivos.

Excluir funções

Funções implantadas previamente podem ser excluídas:

  • explicitamente na CLI do Firebase com functions:delete
  • explicitamente no console do Google Cloud.
  • implicitamente, ao remover a função da origem antes da implantação.

Em todas as operações é necessário confirmar antes de remover a função da produção.

A exclusão explícita de funções na CLI do Firebase aceita vários argumentos, assim como grupos de funções, e permite especificar uma função executada em uma região específica. Além disso, você pode substituir o prompt de confirmação.

# 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

Com a exclusão implícita de funções, firebase deploy analisa a origem e remove da produção todas as funções que foram removidas do arquivo.

Modificar o nome, a região ou o gatilho de uma função

Se você for renomear ou alterar a região ou o gatilho para funções que lidam com o tráfego de produção, siga as etapas desta seção a fim de evitar a perda de eventos durante a modificação. Antes de prosseguir, verifique se a função é idempotente, já que a versão antiga e a nova serão executadas simultaneamente durante a modificação.

Renomear uma função

Para renomear uma função, crie uma nova versão renomeada da função na origem e execute dois comandos de implantação separados. O primeiro comando implanta a função recém-nomeada e o segundo remove a versão implementada anteriormente. Por exemplo, se você tiver uma função Node.js chamada webhook e quiser alterá-la para webhookNew, revise o código da seguinte maneira:

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

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

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

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

Em seguida, execute os seguintes comandos para implantar a nova função:

# 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

Alterar a região ou as regiões de uma função

Se você alterar as regiões especificadas de uma função que lida com tráfego de produção, é possível evitar a perda de eventos executando as etapas na ordem a seguir:

  1. Renomeie a função e altere a região ou as regiões dela, conforme quiser.
  2. Implante a função renomeada, o que resulta na execução temporária do mesmo código nos dois conjuntos de regiões.
  3. Exclua a função anterior.

Por exemplo, se você tiver uma função chamada webhook que esteja atualmente na região de funções padrão de us-central1 e quiser migrá-la para asia-northeast1, primeiro será necessário modificar o código-fonte para renomear a função e revisar a região.

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

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

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

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

Em seguida, implante executando o comando:

firebase deploy --only functions:webhookAsia

Agora, há duas funções idênticas em execução: webhook está em execução em us-central1, enquanto webhookAsia está em execução em asia-northeast1.

Em seguida, exclua webhook:

firebase functions:delete webhook

Agora, há apenas uma função: webhookAsia, que está sendo executada em asia-northeast1.

Alterar o tipo de gatilho de uma função

À medida que você desenvolve sua implantação do Cloud Functions for Firebase ao longo do tempo, pode ser necessário alterar o tipo de gatilho de uma função por vários motivos. Por exemplo, é possível mudar de um tipo de evento Firebase Realtime Database ou Cloud Firestore para outro.

Não é possível alterar o tipo de evento de uma função apenas alterando o código-fonte e executando firebase deploy. Para evitar erros, altere o tipo de gatilho de uma função ao seguir este procedimento:

  1. Modifique o código-fonte para incluir uma nova função com o tipo de gatilho desejado.
  2. Implante a função, o que resulta na execução temporária da função antiga e da nova.
  3. Exclua explicitamente a função antiga da produção usando a CLI do Firebase.

Por exemplo, se você tiver uma função Node.js chamada objectChanged com o tipo de evento legado onChange e quiser alterá-la para onFinalize, renomeie a função e edite-a para ter o tipo de evento onFinalize.

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

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

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

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

Em seguida, execute os seguintes comandos para criar a nova função primeiro, antes de excluir a função antiga:

# 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

Definir opções do ambiente de execução

Com o Cloud Functions for Firebase, é possível selecionar opções de ambiente de execução, como a versão do ambiente de execução do Node.js, o tempo limite por função, a alocação de memória e a quantidade mínima/máxima de instâncias de função.

É prática recomendada que essas opções, exceto pela versão do Node.js, sejam definidas em um objeto de configuração dentro do código da função. O objeto RuntimeOptions é a fonte de verdade para as opções de ambiente de execução da sua função e vai substituir as opções definidas por qualquer outro método, como o console do Google Cloud ou a CLI gcloud.

Se o seu fluxo de trabalho de desenvolvimento envolver a configuração manual de opções de ambiente de execução usando o Console do Google Cloud ou a CLI gcloud e você não quiser que esses valores sejam substituídos em cada implantação, defina a opção preserveExternalChanges como true. Com essa opção definida como true, o Firebase mescla as opções de ambiente de execução definidas no seu código com as configurações da versão atualmente implantada da função na prioridade a seguir:

  1. A opção está definida no código de funções: substituir as alterações externas.
  2. A opção está definida como RESET_VALUE no código das funções: substituir as alterações externas pelo valor padrão.
  3. A opção não está definida no código de funções, mas está configurada na função implantada atualmente: usar a opção especificada na função implantada.

O uso da opção preserveExternalChanges: true não é recomendado na maioria dos casos, porque o código deixa de ser a fonte de verdade completa das opções de ambiente de execução para suas funções. Se for usar essa opção, verifique o console do Google Cloud ou use a CLI gcloud para consultar a configuração completa de uma função.

Definir a versão do Node.js

O SDK do Firebase para Cloud Functions permite selecionar o ambiente de execução do Node.js. É possível executar exclusivamente todas as funções em um projeto apenas no ambiente de execução correspondente a uma dessas versões do Node.js com suporte:

  • Node.js 20 (visualização)
  • Node.js 18
  • Node.js 16
  • Node.js 14

Para definir a versão do Node.js, faça o seguinte:

É possível definir a versão no campo engines no arquivo package.json que foi criado no diretório functions/ durante a inicialização. Por exemplo, para usar apenas a versão 18, edite esta linha em package.json:

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

Ao usar o gerenciador de pacotes Yarn ou ter outros requisitos específicos para o campo engines, há a alternativa de definir o ambiente de execução do SDK do Firebase para Cloud Functions em firebase.json:

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

A CLI usa o valor definido em firebase.json em vez de qualquer valor ou intervalo definido separadamente em package.json.

Fazer upgrade do ambiente de execução do Node.js

Para fazer upgrade do ambiente de execução do Node.js, siga as etapas a seguir:

  1. Verifique se o projeto está no plano de preços Blaze.
  2. Verifique se você está usando a CLI do Firebase v11.18.0 ou mais recente.
  3. Altere o valor engines no arquivo package.json criado no diretório functions/ durante a inicialização. Por exemplo, se você estiver fazendo upgrade da versão 16 para a versão 18, a entrada terá esta aparência: "engines": {"node": "18"}
  4. Também é possível testar suas alterações usando o Firebase Local Emulator Suite.
  5. Reimplante todas as funções.

Controlar o comportamento de escalonamento

Por padrão, o Cloud Functions for Firebase escalona o número de instâncias em execução com base no número de solicitações recebidas. Isso pode reduzir até zero a quantidade de instâncias em períodos de tráfego menor. No entanto, se o app exigir latência reduzida, e você quiser limitar o número de inicializações a frio, altere esse comportamento padrão especificando um número mínimo de instâncias de contêiner a serem mantidas em modo de espera e prontas para exibir solicitações.

Da mesma forma, é possível definir um número máximo para limitar o escalonamento de instâncias em resposta a solicitações recebidas. Use essa configuração como uma maneira de controlar seus custos ou de limitar o número de conexões com um serviço de apoio, como um banco de dados.

Reduzir o número de inicializações a frio

Para definir o número mínimo de instâncias em uma função no código-fonte, use o método runWith. Esse método aceita um objeto JSON em conformidade com a interface RuntimeOptions, que define o valor de minInstances. Por exemplo, esta função define um mínimo de cinco instâncias que devem ser mantidas em modo de espera:

exports.getAutocompleteResponse = functions
    .runWith({
      // Keep 5 instances warm for this latency-critical function
      minInstances: 5,
    })
    .https.onCall((data, context) => {
      // Autocomplete a user's search term
    });

Veja alguns pontos a serem considerados ao definir um valor para minInstances:

  • Se o Cloud Functions for Firebase escalonar o app acima da configuração minInstances, uma inicialização a frio será feita para cada instância acima desse limite.
  • Inicializações a frio afetam de forma mais grave os apps que têm aumento de tráfego. Se o app apresentar picos de tráfego, e um valor de minInstances alto o suficiente for definido para que as inicializações a frio sejam reduzidas a cada aumento, você vai notar que a latência vai ser bem menor. Para apps com tráfego constante, inicializações a frio não afetam muito o desempenho.
  • Definir um limite de instâncias mínimas é uma boa ideia para ambientes de produção, mas isso geralmente deve ser evitado em ambientes de teste. Para reduzir a escala a zero no projeto de teste e seguir diminuindo as inicializações a frio no projeto de produção, defina minInstances com base na variável de ambiente FIREBASE_CONFIG:

    // Get Firebase project id from `FIREBASE_CONFIG` environment variable
    const envProjectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
    
    exports.renderProfilePage = functions
        .runWith({
          // Keep 5 instances warm for this latency-critical function
          // in production only. Default to 0 for test projects.
          minInstances: envProjectId === "my-production-project" ? 5 : 0,
        })
        .https.onRequest((req, res) => {
          // render some html
        });
    

Limitar o número máximo de instâncias para uma função

Para definir o máximo de instâncias no código-fonte da função, use o método runWith. Esse método aceita um objeto JSON em conformidade com a interface RuntimeOptions, que define valores para maxInstances. Por exemplo, esta função define um limite de 100 instâncias para não sobrecarregar um banco de dados legado hipotético:

exports.mirrorOrdersToLegacyDatabase = functions
    .runWith({
      // Legacy database only supports 100 simultaneous connections
      maxInstances: 100,
    })
    .firestore.document("orders/{orderId}")
    .onWrite((change, context) => {
      // Connect to legacy database
    });

Se uma função HTTP for escalonada até o limite de maxInstances, as novas solicitações vão ser enfileiradas por 30 segundos e rejeitadas com um código de resposta 429 Too Many Requests se nenhuma instância estiver disponível depois desse tempo.

Para saber mais sobre as práticas recomendadas para o uso das configurações de instâncias máximas, confira estas práticas recomendadas para usar maxInstances.

Definir o tempo limite e a alocação de memória

Em alguns casos, suas funções podem ter requisitos especiais para um valor de tempo limite longo ou uma grande alocação de memória. Você pode definir esses valores no Console do Google Cloud ou no código-fonte da função (somente no Firebase).

Para definir a alocação de memória e o tempo limite no código-fonte das funções, use o parâmetro runWith introduzido no SDK do Firebase para Cloud Functions 2.0.0. Essa opção de ambiente de execução aceita um objeto JSON em conformidade com a interface RuntimeOptions, que define os valores de timeoutSeconds e memory. Por exemplo, essa função de armazenamento usa 1 GB de memória e expira após 300 segundos:

exports.convertLargeFile = functions
    .runWith({
      // Ensure the function has enough memory and time
      // to process large files
      timeoutSeconds: 300,
      memory: "1GB",
    })
    .storage.object()
    .onFinalize((object) => {
      // Do some complicated things that take a lot of memory and time
    });

O valor máximo para timeoutSeconds é 540 ou 9 minutos. A quantidade de memória concedida a uma função corresponde à CPU alocada para a função, conforme detalhado nesta lista de valores válidos para memory:

  • 128MB — 200MHz
  • 256MB — 400MHz
  • 512MB — 800MHz
  • 1GB — 1,4 GHz
  • 2GB — 2,4 GHz
  • 4GB — 4,8 GHz
  • 8GB — 4,8 GHz

Para definir a alocação de memória e o tempo limite no console do Google Cloud:

  1. No console do Google Google Cloud, selecione Cloud Functions no menu à esquerda.
  2. Clique no nome de uma função para selecioná-la em uma lista de funções.
  3. Clique no ícone Editar no menu na parte superior.
  4. Selecione uma alocação de memória no menu suspenso Memória alocada.
  5. Clique em Mais para exibir as opções avançadas e insira um número de segundos na caixa de texto Tempo limite.
  6. Clique em Salvar para atualizar a função.