Ambiente de execução do Cloud Run 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.

As atualizações de segurança e manutenção são disponibilizadas para todos os ambientes de execução do Cloud Run functions e do Cloud Run functions (1ª 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.

As imagens do ambiente de execução são hospedadas em todas as regiões onde o Artifact Registry está disponível. Você pode personalizar o caminho da imagem do ambiente de execução substituindo a primeira parte do URI pela região de sua escolha:

REGION-docker.pkg.dev/serverless-runtimes/STACK/runtimes/RUNTIME_ID

Substitua:

  • REGION pela região preferencial, por exemplo, us-central1.
  • STACK pela pilha de sistema operacional preferencial, por exemplo, google-22-full.
  • RUNTIME_ID pelo ID do ambiente de execução usado pela função como, por exemplo, python310.

Por exemplo, a imagem base mais recente do Node.js 20 usando a pilha google-22-full, hospedada em us-central1 seria referenciada com este URL: us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22

Node.js

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
Node.js 22 Run functions nodejs22 google-22-full google-22-full/nodejs22
Node.js 20 1a geração, Run functions nodejs20 google-22-full google-22-full/nodejs20
Node.js 18 1a geração, Run functions nodejs18 google-22-full google-22-full/nodejs18
Node.js 16 1a geração, Run functions nodejs16 google-18-full google-18-full/nodjes16
Node.js 14 1a geração, Run functions nodejs14 google-18-full google-18-full/nodjes14
Node.js 12 1a geração, Run functions nodejs12 google-18-full google-18-full/nodjes14
Node.js 10 1a geração, Run functions nodejs10 google-18-full google-18-full/nodjes10
Node.js 8 1a geração, Run functions nodejs8 Desativado Desativado
Node.js 6 1a geração, Run functions nodejs6 Desativado Desativado

Python

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
Python 3.12 1a geração, Run functions python312 google-22-full google-22-full/python312
Python 3.11 1a geração, Run functions python311 google-22-full google-22-full/python311
Python 3.10 1a geração, Run functions python310 google-22-full google-22-full/python310
Python 3.9 1a geração, Run functions python39 google-18-full google-18-full/python39
Python 3.8 1a geração, Run functions python38 google-18-full google-18-full/python38
Python 3.7 1a geração, Run functions python37 google-18-full google-18-full/python37

Go

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
Go 1.23
(apenas pré-lançamento)
Run functions go123 google-22-full google-22-full/go123
Go 1.22 Run functions go122 google-22-full google-22-full/go122
Go 1.21 Run functions go121 google-22-full google-22-full/go121
Go 1.20 Run functions go120 google-22-full google-22-full/go120
Go 1.19 1a geração, Run functions go119 google-22-full google-22-full/go119
Go 1.18 1a geração, Run functions go118 google-22-full google-22-full/go120
Go 1.16 1a geração, Run functions go116 google-18-full google-18-full/go116
Go 1.13 1a geração, Run functions go113 google-18-full google-18-full/go113
Go 1.11 1a geração, Run functions go111 Desativado Desativado

Java

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
Java 21 Run functions java21 google-22-full google-22-full/java21
Java 17 1a geração, Run functions java17 google-22-full google-22-full/java17
Java 11 1a geração, Run functions java11 google-18 google-18/java11

Ruby

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
Ruby 3.3 1a geração, Run functions ruby33 google-22-full google-22-full/ruby33
Ruby 3.2 1a geração, Run functions ruby32 google-22-full google-22-full/ruby32
Ruby 3.0 1a geração, Run functions ruby30 google-18-full google-18-full/ruby30
Ruby 2.7 1a geração, Run functions ruby27 google-18-full google-18-full/ruby27
Ruby 2.6 1a geração, Run functions ruby26 google-18-full google-18-full/ruby26

PHP

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
PHP 8.3 Run functions php83 google-22-full google-22-full/php83
PHP 8.2 1a geração, Run functions php82 google-22-full google-22-full/php82
PHP 8.1 1a geração, Run functions php81 google-18-full google-18-full/php81
PHP 7.4 1a geração, Run functions php74 google-18-full google-18-full/php74

.NET Core

Ambiente de execução Geração ID do ambiente de execução Pilhas Imagem de base do ambiente de execução
.NET Core 8 Run functions dotnet8 google-22-full google-22-full/dotnet8
.NET Core 6 1a geração, Run functions dotnet6 google-22-full google-22-full/dotnet6
.NET Core 3 1a geração, Run functions dotnet3 google-18-full google-18-full/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

O Cloud Run functions aceita 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.