Gerenciar funções


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

Implantar funções

Para implantar funções, execute este comando Firebase CLI:

firebase deploy --only functions

Por padrão, a CLI do Firebase implanta todas as funções dentro da sua fonte ao mesmo tempo. Se o seu projeto contiver mais de cinco funções, recomendamos que você use o sinalizador --only com nomes de funções específicos para implantar apenas as funções que você editou. A implantação de funções específicas dessa forma acelera o processo de implantação e ajuda a evitar atingir cotas de implantação. Por exemplo:

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

Ao implantar um grande número de funções, você poderá exceder a cota padrão e receber mensagens de erro HTTP 429 ou 500. Para resolver isso, implante funções em grupos de 10 ou menos.

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

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

Excluir funções

Você pode excluir funções implantadas anteriormente destas maneiras:

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

Todas as operações de exclusão solicitam confirmação antes de remover a função da produção.

A exclusão explícita de funções na CLI do Firebase oferece suporte a vários argumentos, bem como grupos de funções, e permite especificar uma função em execução 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 sua origem e remove da produção todas as funções que foram removidas do arquivo.

Modifique o nome, região ou gatilho de uma função

Se você estiver renomeando ou alterando as regiões ou o gatilho para funções que manipulam o tráfego de produção, siga as etapas nesta seção para evitar a perda de eventos durante a modificação. 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.

Renomear uma função

Para renomear uma função, crie uma nova versão renomeada da função em sua origem e execute dois comandos de implantação separados. O primeiro comando implanta a função recém-nomeada e o segundo comando remove a versão implantada anteriormente. Por exemplo, se você tiver um webhook acionado por HTTP que gostaria de renomear, revise o código da seguinte maneira:

Node.js

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

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

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

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

Pitão

# before
from firebase_functions import https_fn

@https_fn.on_request()
def webhook(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

# after
from firebase_functions import https_fn

@https_fn.on_request()
def webhook_new(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

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

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

# Wait until deployment is done; now both functions are running

# Delete webhook
firebase functions:delete webhook

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

Se estiver alterando as regiões especificadas para uma função que lida com o tráfego de produção, você poderá evitar a perda de eventos executando estas etapas na ordem:

  1. Renomeie a função e altere sua região ou regiões conforme desejado.
  2. Implante a função renomeada, o que resulta na execução temporária do mesmo código em ambos os conjuntos de regiões.
  3. Exclua a função anterior.

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

Node.js

// before
exports.firestoreTrigger = onDocumentCreated(
  "my-collection/{docId}",
  (event) => {},
);

// after
exports.firestoreTriggerAsia = onDocumentCreated(
  {
    document: "my-collection/{docId}",
    region: "asia-northeast1",
  },
  (event) => {},
);

O código atualizado deve especificar o filtro de eventos correto (neste caso document ) junto com a região. Consulte Locais do Cloud Functions para obter mais informações.

Pitão

# Before
@firestore_fn.on_document_created("my-collection/{docId}")
def firestore_trigger(event):
    pass

# After
@firestore_fn.on_document_created("my-collection/{docId}",
                                  region="asia-northeast1")
def firestore_trigger_asia(event):
    pass

Em seguida, implante executando:

firebase deploy --only functions:firestoreTriggerAsia

Agora existem duas funções idênticas em execução: firestoreTrigger está em execução em us-central1 e firestoreTriggerAsia está em execução em asia-northeast1 .

Em seguida, exclua firestoreTrigger :

firebase functions:delete firestoreTrigger

Agora há apenas uma função - firestoreTriggerAsia , 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 para Firebase ao longo do tempo, pode ser necessário alterar o tipo de gatilho de uma função por vários motivos. Por exemplo, você pode querer mudar de um tipo de evento do Firebase Realtime Database ou do Cloud Firestore para outro tipo.

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 com 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 das funções antigas e novas.
  3. Exclua explicitamente a função antiga da produção usando a CLI do Firebase.

Por exemplo, se você tinha uma função que foi acionada quando um objeto foi excluído, mas ativou o controle de versão do objeto e gostaria de assinar o evento de arquivamento, primeiro renomeie a função e edite-a para ter o novo tipo de acionador.

Node.js

// before
const {onObjectDeleted} = require("firebase-functions/v2/storage");

exports.objectDeleted = onObjectDeleted((event) => {
    // ...
});

// after
const {onObjectArchived} = require("firebase-functions/v2/storage");

exports.objectArchived = onObjectArchived((event) => {
    // ...
});

Pitão

# before
from firebase_functions import storage_fn

@storage_fn.on_object_deleted()
def object_deleted(event):
  # ...

# after 
from firebase_functions import storage_fn

@storage_fn.on_object_archived()
def object_archived(event):
  # ...

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

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

# Wait until deployment is done; now both objectDeleted and objectArchived are running

# Delete objectDeleted
firebase functions:delete objectDeleted

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

O Cloud Functions para Firebase permite selecionar opções de tempo de execução, como a versão do tempo de execução do Node.js e o tempo limite por função, a alocação de memória e instâncias de função mínima/máxima.

Como prática recomendada, essas opções (exceto para a versão Node.js) devem ser definidas em um objeto de configuração dentro do código da função. Este objeto RuntimeOptions é a fonte da verdade para as opções de tempo de execução da sua função e substituirá as opções definidas por qualquer outro método (como por meio do console do Google Cloud ou da CLI gcloud).

Se o seu fluxo de trabalho de desenvolvimento envolver a configuração manual de opções de tempo de execução por meio do console do Google Cloud ou da 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 esta opção definida como true , o Firebase mescla as opções de tempo de execução definidas no seu código com as configurações da versão atualmente implantada da sua função com a seguinte prioridade:

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

Usar a opção preserveExternalChanges: true não é recomendado para a maioria dos cenários porque seu código não será mais a fonte completa de verdade para opções de tempo de execução para suas funções. Se você usá-lo, verifique o console do Google Cloud ou use a CLI gcloud para visualizar a configuração completa de uma função.

Definir versão do Node.js.

O SDK do Firebase para Cloud Functions permite uma seleção de tempo de execução do Node.js. Você pode optar por executar todas as funções em um projeto exclusivamente no ambiente de tempo de execução correspondente a uma destas versões suportadas do Node.js:

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

Para definir a versão do Node.js:

Você pode definir a versão no campo engines no arquivo package.json que foi criado em seu 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"}

Se você estiver usando o gerenciador de pacotes Yarn ou tiver outros requisitos específicos para o campo engines , poderá definir o tempo 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 preferência a qualquer valor ou intervalo definido separadamente em package.json .

Atualize seu tempo de execução do Node.js.

Para atualizar seu tempo de execução do Node.js:

  1. Certifique-se de que seu projeto esteja no plano de preços Blaze .
  2. Verifique se você está usando o Firebase CLI v11.18.0 ou posterior.
  3. Altere o valor engines no arquivo package.json que foi criado em seu diretório functions/ durante a inicialização. Por exemplo, se você estiver atualizando da versão 16 para a versão 18, a entrada deverá ser semelhante a esta: "engines": {"node": "18"}
  4. Opcionalmente, teste suas alterações usando o Firebase Local Emulator Suite .
  5. Reimplante todas as funções.

Definir versão do Python

O SDK do Firebase para Cloud Functions versões 12.0.0 e posteriores permitem a seleção do ambiente de execução do Python. Defina a versão do tempo de execução em firebase.json conforme mostrado:

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

Controlar o comportamento de dimensionamento

Por padrão, o Cloud Functions para Firebase dimensiona o número de instâncias em execução com base no número de solicitações recebidas, reduzindo potencialmente para zero instâncias em momentos de tráfego reduzido. No entanto, se seu aplicativo exigir latência reduzida e você quiser limitar o número de inicializações a frio, poderá alterar esse comportamento padrão especificando um número mínimo de instâncias de contêiner a serem mantidas aquecidas e prontas para atender solicitações.

Da mesma forma, você pode definir um número máximo para limitar o dimensionamento de instâncias em resposta às solicitações recebidas. Use esta configuração como uma forma de controlar seus custos ou limitar o número de conexões com um serviço de apoio, como um banco de dados.

Usando essas configurações junto com a configuração de simultaneidade por instância (nova na 2ª geração), você pode controlar e ajustar o comportamento de dimensionamento para suas funções. A natureza da sua aplicação e função determinará quais configurações são mais econômicas e resultarão no melhor desempenho.

Para alguns aplicativos com baixo tráfego, uma opção de CPU menor sem multisimultaneidade é ideal. Para outros onde as inicializações a frio são um problema crítico, definir alta simultaneidade e instâncias mínimas significa que um conjunto de instâncias é sempre mantido quente para lidar com grandes picos de tráfego.

Para aplicativos de menor escala que recebem muito pouco tráfego, definir instâncias máximas baixas com alta simultaneidade significa que o aplicativo pode lidar com picos de tráfego sem incorrer em custos excessivos. No entanto, lembre-se de que quando o número máximo de instâncias for definido como muito baixo, as solicitações poderão ser descartadas quando o limite máximo for atingido.

Permitir solicitações simultâneas

No Cloud Functions para Firebase (1ª geração), cada instância podia processar uma solicitação por vez, portanto, o comportamento de escalonamento era definido apenas com configurações mínimas e máximas de instâncias. Além de controlar o número de instâncias, no Cloud Functions para Firebase (2ª geração) você pode controlar o número de solicitações que cada instância pode atender ao mesmo tempo com a opção de concurrency . O valor padrão para simultaneidade é 80, mas você pode defini-lo como qualquer número inteiro entre 1 e 1.000.

Funções com configurações de simultaneidade mais altas podem absorver picos de tráfego sem inicialização a frio porque cada instância provavelmente tem algum espaço livre. Se uma instância estiver configurada para lidar com até 50 solicitações simultâneas, mas atualmente estiver processando apenas 25, ela poderá lidar com um pico de 25 solicitações adicionais sem exigir uma nova instância para inicialização a frio. Por outro lado, com uma configuração de simultaneidade de apenas 1, esse aumento nas solicitações poderia levar a 25 inicializações a frio.

Este cenário simplificado demonstra os potenciais ganhos de eficiência da simultaneidade. Na realidade, o comportamento de dimensionamento para otimizar a eficiência e reduzir as partidas a frio com simultaneidade é mais complexo. A simultaneidade no Cloud Functions para Firebase de segunda geração é desenvolvida pelo Cloud Run e segue as regras de escalonamento automático de instâncias de contêiner do Cloud Run.

Ao testar configurações de simultaneidade mais altas no Cloud Functions para Firebase (2ª geração), lembre-se do seguinte:

  • Configurações de simultaneidade mais altas podem exigir CPU e RAM mais altas para desempenho ideal até atingir um limite prático. Uma função que realiza processamento pesado de imagem ou vídeo, por exemplo, pode não ter recursos para lidar com 1.000 solicitações simultâneas, mesmo quando suas configurações de CPU e RAM estão maximizadas.
  • Como o Cloud Functions para Firebase (2ª geração) é desenvolvido com Cloud Run, você também pode consultar as orientações do Google Cloud para otimizar a simultaneidade .
  • Certifique-se de testar minuciosamente a multisimultaneidade em um ambiente de teste antes de mudar para multisimultaneidade na produção.

Mantenha um número mínimo de instâncias aquecidas

Você pode definir o número mínimo de instâncias para uma função no código-fonte. Por exemplo, esta função define um mínimo de 5 instâncias para se manter aquecido:

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

Pitão

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

Aqui estão algumas coisas a serem consideradas ao definir um valor mínimo de instâncias:

  • Se o Cloud Functions para Firebase dimensionar seu aplicativo acima da configuração, você terá uma inicialização a frio para cada instância acima desse limite.
  • As inicializações a frio têm o efeito mais severo em aplicativos com tráfego intenso. Se seu aplicativo tiver tráfego intenso e você definir um valor alto o suficiente para que as inicializações a frio sejam reduzidas a cada aumento de tráfego, você verá uma latência significativamente reduzida. Para aplicativos com tráfego constante, as inicializações a frio provavelmente não afetarão gravemente o desempenho.
  • Definir instâncias mínimas pode fazer sentido para ambientes de produção, mas geralmente deve ser evitado em ambientes de teste. Para escalar para zero em seu projeto de teste, mas ainda reduzir inicializações a frio em seu projeto de produção, você pode definir um valor mínimo de instâncias em sua configuração 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.`);
      }
    );
    

    Pitão

    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.")
    

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

Você pode definir um valor para o máximo de instâncias no código-fonte da função. Por exemplo, esta função define um limite de 100 instâncias para não sobrecarregar um hipotético banco de dados legado:

Node.js

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

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

Pitão

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

Se uma função HTTP for ampliada até o limite máximo de instâncias, novas solicitações serão enfileiradas por 30 segundos e depois rejeitadas com um código de resposta de 429 Too Many Requests se nenhuma instância estiver disponível até então.

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

Definir tempo limite e 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 Firebase).

Para definir a alocação de memória e o tempo limite no código-fonte das funções, use as opções globais de memória e segundos de tempo limite para personalizar a máquina virtual que executa suas funções. Por exemplo, esta função do Cloud Storage usa 1 GiB de memória e atinge o tempo limite após 300 segundos:

Node.js

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

Pitão

@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.

O valor máximo para segundos de tempo limite é 540 ou 9 minutos.

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

  1. No console do Google Cloud, selecione Cloud Functions para Firebase no menu esquerdo.
  2. Selecione uma função clicando em seu nome na lista de funções.
  3. Clique no ícone Editar no menu superior.
  4. Selecione uma alocação de memória no menu suspenso denominado 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.

Substituir padrões de CPU

Até 2 GB de memória alocada, cada função no Cloud Functions para Firebase (2ª geração) tem como padrão uma CPU e depois aumenta para 2 CPUs para 4 e 8 GB. Observe que isso é significativamente diferente do comportamento padrão da 1ª geração de maneiras que podem levar a custos ligeiramente mais elevados para funções com pouca memória, conforme expresso na tabela a seguir:

RAM alocada CPU padrão da versão 1 (fracionária) CPU padrão da versão 2 Aumento de preço 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 12/07 1 1,6x
2 GB 1 1 1x
4GB 2 2 1x
8 GB 2 2 1x
16 GB n / D 4 n / D

Se você preferir o comportamento de 1ª geração para suas funções de 2ª geração, defina os padrões de 1ª geração como uma opção global:

Node.js

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

Pitão

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

Para funções com uso intensivo de CPU, a 2ª geração oferece flexibilidade para configurar CPU adicional. Você pode aumentar a CPU por função, conforme mostrado:

Node.js

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

Pitão

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