Dicas e truques
Neste documento, descrevemos as práticas recomendadas para projetar, implementar, testar e implantar o Cloud Run functions.
Correção
Nesta seção, você verá as práticas recomendadas gerais para projetar e implementar o Cloud Run functions.
Escreva funções idempotentes
As funções devem produzir o mesmo resultado, mesmo que sejam chamadas várias vezes. Isso permite que você tente executar uma invocação novamente caso a anterior falhe no seu código. Para mais informações, consulte Como repetir funções baseadas em eventos.
Confirme se as funções HTTP enviam uma resposta HTTP
Se a função for acionada por HTTP, lembre-se de enviar uma resposta HTTP, como mostrado abaixo. Não fazer isso pode resultar na execução da função até o tempo limite. Se isso ocorrer, você será cobrado por todo o tempo limite. Os tempos limite também podem causar um comportamento imprevisível ou inicializações a frio em invocações subsequentes, resultando em um comportamento imprevisível ou latência adicional.
Node.js
Python
Go
Java
C#
Ruby
PHP
Não inicie atividades em segundo plano
Atividade em segundo plano é tudo que ocorre depois que a função é encerrada.
A invocação de uma função termina quando a função retorna ou sinaliza
a conclusão, por exemplo, chamando o argumento callback
nas funções orientadas por eventos
do Node.js. Qualquer código executado após a finalização normal não pode acessar a CPU e não progredirá.
Além disso, quando uma invocação subsequente é executada no mesmo ambiente, a atividade em segundo plano é retomada, interferindo na nova invocação. Isso pode levar a um comportamento inesperado e erros difíceis de diagnosticar. O acesso à rede depois que uma função é concluída normalmente causa a redefinição das conexões (código do erro ECONNRESET
).
Ela normalmente pode ser detectada em registros de invocações individuais, encontrando tudo o que será registrado depois da linha que informa sobre o término da invocação. Às vezes, a atividade em segundo plano pode ser aprofundada no código, especialmente quando operações assíncronas, como callbacks ou timers, estão presentes. Revise o código para verificar se todas as operações assíncronas foram concluídas antes de você finalizar a função.
Sempre exclua arquivos temporários
O armazenamento de disco local no diretório temporário é um sistema de arquivos na memória. Os arquivos que você grava consomem memória disponível para sua função e, às vezes, permanecem entre as invocações. A não exclusão deles pode resultar em um erro de memória insuficiente e uma subsequente inicialização a frio.
Confira a memória usada por uma função individual selecionando-a na lista de funções do Google Cloud console e escolhendo o gráfico Uso da memória.
Se você precisar de acesso ao armazenamento de longo prazo, use as montagens de volume do Cloud Run com o Cloud Storage ou os volumes do NFS.
É possível reduzir os requisitos de memória ao processar arquivos maiores usando pipelines. Por exemplo, processe um arquivo no Cloud Storage criando um stream de leitura, transmitindo-o por um processo baseado em stream e gravando o stream de saída diretamente no Cloud Storage.
Functions Framework
Para garantir que as mesmas dependências sejam instaladas de maneira consistente em diferentes ambientes, recomendamos que você inclua a biblioteca do Functions Framework no gerenciador de pacotes e fixe a dependência a uma versão específica do Functions Framework.
Para isso, inclua a versão de sua preferência no arquivo de bloqueio relevante
(por exemplo, package-lock.json
para Node.js ou requirements.txt
para Python).
Se o Functions Framework não estiver listado explicitamente como uma dependência, ele será adicionado automaticamente durante o processo de build usando a versão mais recente disponível.
Ferramentas
Nesta seção, você verá diretrizes sobre como usar ferramentas para implementar, testar e interagir com o Google Run functions.
Desenvolvimento local
A implantação de funções demora um pouco, então geralmente é mais rápido testar o código da sua função localmente.
Error Reporting
Em linguagens que usam processamento de exceção, não crie exceções não capturadas, pois elas forçam inicialização a frio em futuras invocações. Consulte o guia do Error Reporting para ver informações sobre como relatar erros corretamente.
Não sair manualmente
Sair manualmente pode causar um comportamento inesperado. Use os seguintes idiomas específicos de linguagem:
Node.js
Não use process.exit()
. As funções HTTP precisam enviar uma resposta com
res.status(200).send(message)
, e as funções
orientadas a eventos sairão quando elas retornarem, implicitamente ou explicitamente.
Python
Não use sys.exit()
. As funções HTTP retornarão
uma resposta como uma string de maneira explícita, e as funções orientadas a eventos sairão assim que
retornarem um valor, implicitamente ou explicitamente.
Go
Não use os.Exit()
. As funções HTTP retornarão
uma resposta como uma string de maneira explícita, e as funções orientadas a eventos sairão assim que
retornarem um valor, implicitamente ou explicitamente.
Java
Não use System.exit()
. As funções HTTP precisam enviar uma resposta com
response.getWriter().write(message)
, e as funções
orientadas a eventos sairão quando elas retornarem, implicitamente ou explicitamente.
C#
Não use System.Environment.Exit()
. As funções HTTP precisam enviar uma resposta com
context.Response.WriteAsync(message)
, e as funções
orientadas a eventos sairão quando elas retornarem, implicitamente ou explicitamente.
Ruby
Não use exit()
ou abort()
. As funções HTTP retornarão
uma resposta como uma string de maneira explícita, e as funções orientadas a eventos sairão assim que
retornarem um valor, implicitamente ou explicitamente.
PHP
Não use exit()
ou die()
. As funções HTTP retornarão
uma resposta como uma string de maneira explícita, e as funções orientadas a eventos sairão assim que
retornarem um valor, implicitamente ou explicitamente.
Use SendGrid para enviar e-mails
O Cloud Run functions não permite conexões de saída na porta 25, então não é possível estabelecer conexões não seguras com um servidor SMTP. A maneira recomendada de enviar e-mails é usar um serviço de terceiros, como o SendGrid. Confira outras opções para enviar e-mails no tutorial Como enviar e-mails a partir de uma instância do Google Compute Engine.
Desempenho
Nesta seção, você verá as práticas recomendadas para otimizar o desempenho.
Use dependências com sabedoria
Como as funções não têm estado, o ambiente de execução normalmente é inicializado do zero, o que é chamado de inicialização a frio. Quando ocorre uma inicialização a frio, o contexto global da função é avaliado.
Se suas funções importam módulos, o tempo de carregamento deles pode ser adicionado à latência de invocação durante uma inicialização a frio. É possível reduzir essa latência, bem como o tempo necessário para implantar sua função, carregando as dependências necessárias e não carregando as dependências que sua função não utiliza.
Use variáveis globais para reutilizar objetos em futuras invocações
Não há garantia de que o estado de um Cloud Run function seja preservado para futuras invocações. No entanto, essas funções reciclam frequentemente o ambiente de execução de uma invocação anterior. Se você declarar uma variável no escopo global, o valor dela pode ser reutilizado em invocações subsequentes sem necessidade de recálculo.
Dessa forma, é possível armazenar em cache os objetos cuja recriação em cada invocação de função pode ser cara. Mover esses objetos do corpo da função para o escopo global pode resultar em melhorias significativas de desempenho. No exemplo a seguir, um objeto pesado é criado apenas uma vez por instância de função e é compartilhado em todas as invocações da função que alcançam a instância determinada:
Node.js
Python
Go
Java
C#
Ruby
PHP
É muito importante fazer o armazenamento em cache de conexões de rede, referências de biblioteca e objetos de cliente de API em escopo global. Consulte Otimizar redes para exemplos.
Faça a inicialização lenta de variáveis globais
Se você inicializar variáveis em escopo global, o código de inicialização sempre será
executado por meio de uma invocação de inicialização a frio, aumentando a latência da função.
Em alguns casos, isso causa tempos limite intermitentes para os serviços que estão sendo chamados
se não forem tratados adequadamente em um bloco try
/catch
. Se alguns objetos não forem usados em todos os caminhos de código, convém inicializá-los somente sob demanda:
Node.js
Python
Go
Java
C#
Ruby
PHP
As funções PHP não preservam variáveis entre solicitações. A amostra de escopos acima usa o carregamento lento para armazenar em cache os valores de variáveis globais em um arquivo.
Isso é importante principalmente se você definir várias funções em um único arquivo e diferentes funções usarem variáveis distintas. A menos que você use a inicialização lenta, poderá desperdiçar recursos em variáveis que são inicializadas, mas nunca usadas.
Reduza a inicialização a frio definindo um número mínimo de instâncias
Por padrão, o Cloud Run functions dimensiona o número de instâncias com base no número de solicitações de entrada. É possível alterar esse comportamento padrão definindo um número mínimo de instâncias que o Cloud Run functions precisa manter prontas para exibir solicitações. Definir um número mínimo de instâncias reduz as inicializações a frio do aplicativo. Recomendamos definir um número mínimo de instâncias se o aplicativo for sensível à latência.
Para saber como definir um número mínimo de instâncias, consulte Como usar o mínimo instâncias.
Outros recursos
Saiba mais sobre como otimizar o desempenho no vídeo do "Atlas de desempenho do Google Cloud", Tempo de inicialização a frio do Cloud Run functions.