Ambiente de execução do Cloud Functions

As funções do Cloud Run são executadas em um ambiente sem servidor totalmente gerenciado, no qual o Google processa infraestrutura, sistemas operacionais e ambientes de execução. Cada função é executada no próprio contexto de execução seguro e isolado, com dimensionamento automático e um ciclo de vida independente de outras funções.

Ambientes de execução

As funções do Cloud Run são compatíveis com ambientes de execução de várias linguagens. Cada um contém um conjunto padrão de pacotes do sistema, assim como as ferramentas e bibliotecas necessárias para essa linguagem. Você precisará do valor do ID do ambiente de execução se estiver implantando funções pela linha de comando, ou pelo Terraform.

Atualizações de segurança e manutenção são disponibilizadas para todos os ambientes de execução da 1a e 2a geração. Essas atualizações são aplicadas de forma automática ou manual, dependendo do ambiente e de como você o configurou. Para mais informações sobre atualizações do ambiente de execução, consulte Proteger as funções do Cloud Run.

Node.js

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
Node.js 22 (somente visualização) Segunda geração Ubuntu 22.04 nodejs22 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22
Node.js 20 1a geração, 2a geração Ubuntu 22.04 nodejs20 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs20
Node.js 18 1a geração, 2a geração Ubuntu 22.04 nodejs18 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs18
Node.js 16 1a geração, 2a geração Ubuntu 18.04 nodejs16 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs16
Node.js 14 1a geração, 2a geração Ubuntu 18.04 nodejs14 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs14
Node.js 12 1a geração, 2a geração Ubuntu 18.04 nodejs12 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs12
Node.js 10 1a geração, 2a geração Ubuntu 18.04 nodejs10 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/nodejs10
Node.js 8 1a geração, 2a geração Ubuntu 18.04 nodejs8 Desativado
Node.js 6 1a geração, 2a geração Ubuntu 18.04 nodejs6 Desativado

Python

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
Python 3.12 1a geração, 2a geração Ubuntu 22.04 python312 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python312
Python 3.11 1a geração, 2a geração Ubuntu 22.04 python311 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python311
Python 3.10 1a geração, 2a geração Ubuntu 22.04 python310 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/python310
Python 3.9 1a geração, 2a geração Ubuntu 18.04 python39 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python39
Python 3.8 1a geração, 2a geração Ubuntu 18.04 python38 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python38
Python 3.7 1ª geração Ubuntu 18.04 python37 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/python37

Go

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
Go 1.22 Segunda geração Ubuntu 22.04 go122 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go122
Go 1.21 1a geração, 2a geração Ubuntu 22.04 go121 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go121
Go 1.20 1a geração, 2a geração Ubuntu 22.04 go120 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go120
Go 1.19 1a geração, 2a geração Ubuntu 22.04 go119 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go119
Go 1.18 1a geração, 2a geração Ubuntu 22.04 go118 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/go118
Go 1.16 1a geração, 2a geração Ubuntu 18.04 go116 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/go116
Go 1.13 1a geração, 2a geração Ubuntu 18.04 go113 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/go113
Go 1.11 1a geração, 2a geração Ubuntu 18.04 go111 Desativado

Java

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
Java 21 Segunda geração Ubuntu 22.04 java21 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/java21
Java 17 1a geração, 2a geração Ubuntu 22.04 java17 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/java17
Java 11 1a geração, 2a geração Ubuntu 18.04 java11 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/java11

Ruby

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
Ruby 3.3 1a geração, 2a geração Ubuntu 22.04 ruby33 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/ruby32
Ruby 3.2 1a geração, 2a geração Ubuntu 22.04 ruby32 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/ruby32
Ruby 3.0 1a geração, 2a geração Ubuntu 18.04 ruby30 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby30
Ruby 2.7 1a geração, 2a geração Ubuntu 18.04 ruby27 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby27
Ruby 2.6 1a geração, 2a geração Ubuntu 18.04 ruby26 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/ruby26

PHP

Ambiente de execução Ambiente Geração ID do ambiente de execução Imagem do ambiente de execução
PHP 8.3 Segunda geração Ubuntu 22.04 php83 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/php83
PHP 8.2 1a geração, 2a geração Ubuntu 22.04 php82 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/php82
PHP 8.1 1a geração, 2a geração Ubuntu 18.04 php81 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/php81
PHP 7.4 1a geração, 2a geração Ubuntu 18.04 php74 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/php74

.NET Core

Ambiente de execução Geração Ambiente ID do ambiente de execução Imagem do ambiente de execução
.NET Core 8 Segunda geração Ubuntu 22.04 dotnet8 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/dotnet8
.NET Core 6 1a geração, 2a geração Ubuntu 22.04 dotnet6 us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/dotnet6
.NET Core 3 1a geração, 2a geração Ubuntu 18.04 dotnet3 us-central1-docker.pkg.dev/serverless-runtimes/google-18-full/runtimes/dotnet3

Comportamento de escalonamento automático

As funções do Cloud Run implementam o paradigma sem servidor, onde você executa seu código sem se preocupar com a infraestrutura subjacente, como servidores e máquinas virtuais. Depois de implantadas, as funções são gerenciadas e escalonadas automaticamente.

As funções do Cloud Run lidam com as solicitações recebidas atribuindo-as a instances da sua função. Dependendo do volume de solicitações e do número de instâncias de função existentes, as funções do Cloud Run podem atribuir uma solicitação a uma instância existente ou criar uma nova.

Nos casos em que o volume de solicitações de entrada excede o número de instâncias existentes, as funções do Cloud Run podem iniciar várias novas instâncias para processar solicitações. Esse comportamento de escalonamento automático permite que as funções do Cloud Run lidem com muitas solicitações em paralelo, cada uma usando uma instância diferente da sua função.

Em alguns casos, o escalonamento ilimitado pode ser indesejável. Para resolver isso, as funções do Cloud Run permitem configurar um número máximo de instâncias que podem coexistir a qualquer momento para uma função específica.

Sem estado

Para permitir o gerenciamento automático e o escalonamento das funções, elas precisam ser sem estado. Uma invocação de função não pode depender do estado na memória definido por uma invocação anterior. As invocações podem ser processadas por instâncias de função diferentes, que não compartilham variáveis globais, memória, sistemas de arquivos ou outro estado.

Se você precisa compartilhar estados em invocações de função, sua função deve usar um serviço como Memorystore, Datastore, Firestore ou Cloud Storage para manter os dados. Consulte bancos de dados do Google Cloud e produtos de armazenamento do Google Cloud para ver mais informações sobre as opções de banco de dados e armazenamento fornecidas pelo Google Cloud.

Simultaneidade

Funções do Cloud Run (2ª geração)

As funções do Cloud Run (2ª geração) são compatíveis com o processamento de várias solicitações simultâneas em uma única instância de função. Isso pode ser útil para evitar inicializações a frio, já que uma instância já aquecida pode processar várias solicitações simultaneamente, reduzindo assim a latência geral. Para detalhes, consulte Simultaneidade.

Funções do Cloud Run (1ª geração)

Nas funções do Cloud Run (1ª geração), cada instância de uma função processa apenas uma solicitação simultânea por vez. Isso quer dizer que o código está processando uma solicitação. Não há possibilidade de uma segunda solicitação ser encaminhada para a mesma instância. Portanto, a solicitação original pode usar toda a quantidade de recursos (memória e CPU) alocados.

Como as solicitações simultâneas nas funções do Cloud Run (1ª geração) são processadas por instâncias de função diferentes, elas não compartilham variáveis nem memória local. Para mais informações, consulte Sem estado e Tempo de vida da instância de função.

Inicializações a frio

Uma nova instância de função é iniciada em dois casos:

  • Quando você implanta a função.

  • Quando uma nova instância de função é criada automaticamente para ser escalonada até a carga ou para substituir uma instância existente às vezes.

O início de uma nova instância de função envolve o carregamento do tempo de execução e do código. As solicitações que incluem inicialização de instância de função, denominadas inicializações a frio, podem ser mais lentas do que as solicitações roteadas para instâncias de função existentes. Porém, se a função receber carga constante, o número de partidas a frio normalmente será insignificante, a menos que a função falhe sempre e exija a reinicialização do ambiente de função.

Se o código de função gerar uma exceção não capturada ou travar o processo atual, a instância da função poderá ser reiniciada. Isso pode levar a mais inicializações a frio, resultando em maior latência. Portanto, recomendamos capturar exceções e evitar o encerramento do processo atual. Consulte Como relatar erros para uma discussão sobre como processar e informar erros nas funções do Cloud Run.

Se a função for sensível à latência, defina um número mínimo de instâncias para evitar inicializações a frio.

Vida útil da instância de função

As instâncias de função normalmente são resilientes e reutilizadas por invocações de função subsequentes, a menos que o número de instâncias esteja sendo reduzido devido à falta de tráfego contínuo ou à falha na função. Isso significa que quando uma execução de função termina, outra invocação pode ser manipulada pela mesma instância.

Escopo de função x escopo global

Uma única invocação de função resulta na execução apenas do corpo da função declarada como o ponto de entrada. O escopo global do código-fonte da função é executado apenas em inicializações a frio, e não em instâncias que já foram inicializadas.

Node.js

const functions = require('@google-cloud/functions-framework');

// TODO(developer): Define your own computations
const {lightComputation, heavyComputation} = require('./computations');

// Global (instance-wide) scope
// This computation runs once (at instance cold-start)
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
functions.http('scopeDemo', (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

  res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
});

Python

import time

import functions_framework


# Placeholder
def heavy_computation():
    return time.time()


# Placeholder
def light_computation():
    return time.time()


# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()


@functions_framework.http
def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return f"Instance: {instance_var}; function: {function_var}"

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
	functions.HTTP("ScopeDemo", ScopeDemo)
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Ruby

# Global (instance-wide) scope.
# This block runs on cold start, before any function is invoked.
#
# Note: It is usually best to run global initialization in an on_startup block
# instead at the top level of the Ruby file. This is because top-level code
# could be executed to verify the function during deployment, whereas an
# on_startup block is run only when an actual function instance is starting up.
FunctionsFramework.on_startup do
  instance_data = perform_heavy_computation

  # To pass data into function invocations, the best practice is to set a
  # key-value pair using the Ruby Function Framework's built-in "set_global"
  # method. Functions can call the "global" method to retrieve the data by key.
  # (You can also use Ruby global variables or "toplevel" local variables, but
  # they can make it difficult to isolate global data for testing.)
  set_global :my_instance_data, instance_data
end

FunctionsFramework.http "tips_scopes" do |_request|
  # Per-function scope.
  # This method is called every time this function is called.
  invocation_data = perform_light_computation

  # Retrieve the data computed by the on_startup block.
  instance_data = global :my_instance_data

  "instance: #{instance_data}; function: #{invocation_data}"
end

É possível usar variáveis globais como uma otimização de desempenho, mas não é possível depender do estado definido no escopo global por invocações de função anteriores. Consulte Sem estado para ver mais informações.

Suponha que, para cada instância de função, o escopo global tenha sido executado exatamente uma vez antes que o código de função seja invocado. No entanto, não dependa do número total nem do tempo das execuções de escopo global, já que elas podem variar dependendo da atividade de escalonamento automático.

Linha do tempo da execução da função

Uma função tem acesso aos recursos alocados (memória e CPU) apenas durante a execução da função. Não é garantido que o código seja executado fora do período de execução. Ele também pode ser interrompido a qualquer momento. Portanto, sempre sinalize o fim da execução da função corretamente e evite executar qualquer código além dela. Para mais orientações, consulte Funções HTTP, Funções em segundo plano e Funções do CloudEvent.

A execução da função também está sujeita à duração do tempo limite da função. Consulte Tempo limite da função para mais informações.

Considere o cronograma de execução ao inicializar seu aplicativo. As tarefas em segundo plano não devem ser criadas no escopo global durante a inicialização, já que serão executadas fora da duração de uma solicitação.

Garantias de execução

As funções normalmente são invocadas uma vez para cada evento recebido. No entanto, as funções do Cloud Run não garantem uma única invocação em todos os casos por causa de diferenças em cenários de erro.

O número máximo ou mínimo de vezes que a função pode ser invocada para um único evento depende do tipo da função:

  • As funções HTTP são invocadas, no máximo, uma vez. Isso acontece por causa da natureza síncrona das chamadas HTTP, e isso significa que qualquer erro no processamento da invocação da função será retornado sem nova tentativa. O autor da chamada de uma função HTTP processará os erros e tentará novamente, se necessário.

  • As funções orientadas a eventos são invocadas pelo menos uma vez. Isso ocorre devido à natureza assíncrona dos eventos, em que não há nenhum autor da chamada aguardando a resposta. Em raras circunstâncias, o sistema poderá invocar uma função orientada a eventos mais de uma vez para garantir a entrega do evento. Se uma invocação da função orientada a eventos falhar com um erro, ela não será invocada novamente, a menos que as novas tentativas em caso de falha estejam ativadas para essa função.

Para garantir que a função se comporte corretamente em tentativas de execução repetidas, você precisa torná-la idempotente implementando-a para que os resultados e efeitos colaterais sejam produzidos mesmo que um evento seja exibido várias vezes. No caso de funções HTTP, isso também indicará o retorno do valor desejado mesmo se o autor da chamada tentar novamente chamadas para o endpoint da função HTTP. Consulte Como repetir funções orientadas a eventos para mais informações sobre como tornar sua função idempotente.

Memória e sistema de arquivos

Cada função tem uma certa quantidade de memória alocada para uso. É possível configurar a quantidade de memória na implantação. Consulte Limites de memória para mais informações.

O ambiente de execução da função inclui um sistema de arquivos na memória que contém os arquivos de origem e diretórios implantados com sua função. Consulte Como estruturar o código-fonte. O diretório que contém os arquivos de origem é somente leitura, mas o restante do sistema de arquivos é gravável (exceto os arquivos usados pelo sistema operacional). O uso do sistema de arquivos é contabilizado no uso da memória de uma função.

Sua função pode interagir com o sistema de arquivos usando métodos padrão em cada linguagem de programação.

Rede

Sua função pode acessar a Internet pública usando métodos padrão em cada linguagem de programação, seja por meio de bibliotecas integradas oferecidas pelo ambiente de execução ou por bibliotecas de terceiros incluídas como dependências.

Tente reutilizar as conexões de rede entre as invocações de função, conforme descrito em Como otimizar a rede. No entanto, uma conexão que permanece sem uso por 10 minutos pode ser fechada pelo sistema, e outras tentativas de usar uma conexão fechada resultam em um erro de "redefinição de conexão". O código precisa usar uma biblioteca que processe bem conexões fechadas ou processá-las explicitamente, caso esteja usando construtos de rede de baixo nível.

Isolamento de funções

Cada função implantada permanece isolada de todas as outras funções, mesmo as implantadas pelo mesmo arquivo de origem. Em especial, elas não compartilham memória, variáveis globais, sistemas de arquivos ou outros estados.

Para compartilhar dados em funções implantadas, é possível usar serviços como Memorystore, Datastore, Firestore ou Cloud Storage. Como alternativa, é possível invocar uma função de outra usando os gatilhos apropriados e transmitindo os dados necessários. Por exemplo, faça uma solicitação HTTP para o endpoint de uma função HTTP ou publique uma mensagem em um tópico Pub/Sub para acionar uma função Pub/Sub.