Desenvolvimento de funções locais

As funções do Cloud Run suportam vários métodos de execução das suas funções fora do ambiente de implementação de destino. Isto é particularmente útil para o desenvolvimento iterativo e para situações em que quer testar a sua função antes da implementação.

A capacidade de executar as suas funções sem as implementar pode simplificar os testes locais, a conformidade com as restrições de localidade dos dados e as implementações em várias nuvens:

  • Restrições de localidade dos dados: teste a sua função localmente sem aceder aos dados de produção para evitar violar as regras de localidade dos dados da sua organização.

  • Implementações em várias nuvens: as implementações de funções em várias nuvens são um padrão estabelecido para mitigar o risco de tempo de inatividade em ambientes críticos para a fiabilidade. A implementação de funções em ambientes diferentes das funções do Cloud Run reduz o risco de a sua aplicação sofrer tempo de inatividade não planeado.

Desenvolva funções localmente com o Functions Framework

Pode desenvolver e testar funções localmente através do Functions Framework. O desenvolvimento de uma função localmente pode ajudar a testar o código sem ter de recompilar o contentor de funções. Isto pode poupar tempo e facilitar o teste da sua função.

O Cloud Run usa as bibliotecas de código aberto do Functions Framework para encapsular as suas funções implementadas numa aplicação HTTP persistente.

O Functions Framework também pode ser executado em qualquer outra plataforma que suporte o próprio idioma, incluindo a sua máquina local, servidores no local e o Compute Engine.

Instale dependências

No diretório da sua função, instale a biblioteca Functions Framework para o seu idioma:

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Ir

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

Se estiver a usar o Maven, adicione o seguinte ao ficheiro pom.xml:

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

Se estiver a usar o Gradle, adicione o seguinte ao ficheiro build.gradle:

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

Consulte a biblioteca Java Functions Framework para mais informações.

C#

Os comandos seguintes usam modelos .NET para criar uma nova base de código da função .NET com a biblioteca.NET Functions Framework como uma dependência:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

Em Ruby, o Functions Framework tem de ser adicionado às dependências da sua função para a implementar no Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configure o Functions Framework

Antes de executar uma função com o Functions Framework, tem de especificar o tipo e o nome da função que quer executar. Estes atributos podem ser especificados como um indicador da interface de linhas de comando (CLI) ou como variáveis de ambiente.

Tipos de funções suportados

O Functions Framework suporta ambos os tipos de funções suportados pelas funções do Cloud Run. Todos os tempos de execução de idiomas suportam os tipos de assinatura http e cloudevent.

Tipo de função Tipo de assinatura Descrição Tempos de execução suportados
Funções acionadas por HTTP http Funções que recebem e respondem a pedidos HTTP. Todos os tempos de execução
Funções orientadas por eventos cloudevent Formato de evento padrão da indústria. Todos os tempos de execução

Especifique a função a executar

Antes de executar uma função com o Functions Framework, tem de especificar que função no seu código quer executar. Para a maioria dos idiomas, pode fazê-lo especificando o nome do método da função de destino, conforme mostrado nas tabelas seguintes. Tenha em atenção que existem exceções a esta regra para os runtimes Java e .NET.

Instruções por idioma

Consulte a tabela seguinte para ver uma lista de opções de configuração suportadas por cada idioma.

Node.js

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para ouvir pedidos. (Predefinição: 8080)
--target FUNCTION_TARGET O nome da função exportcom nome a ser invocada. (Predefinição: function)
--signature-type FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela sua função. Pode ser http (a predefinição) ou cloudevent.

Python

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para ouvir pedidos. (Predefinição: 8080)
--target FUNCTION_TARGET O nome da função exportcom nome a ser invocada. (Predefinição: function)
--signature-type FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela sua função. Pode ser http (a predefinição) ou cloudevent.

Ir

Variável de ambiente Descrição
PORT A porta para ouvir pedidos. (Predefinição: 8080)

Java

Nome do argumento Variável de ambiente Descrição
run.port PORT A porta para ouvir pedidos. (Predefinição: 8080)
run.functionTarget FUNCTION_TARGET O nome da função exportcom nome a ser invocada. (Predefinição: function)

C#

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para ouvir pedidos. (Predefinição: 8080)
--target (ou único argumento) FUNCTION_TARGET O nome da classe da função a invocar. (Predefinição: function)

Ruby

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para ouvir pedidos. (Predefinição: 8080)
--target FUNCTION_TARGET O nome da função exportcom nome a ser invocada. (Predefinição: function)

PHP

Variável de ambiente Descrição
FUNCTION_TARGET O nome da função a invocar. (Predefinição: function)
FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela sua função. Pode ser http (a predefinição) ou cloudevent.

Siga estas instruções para configurar e executar o Functions Framework:

Node.js

O framework de funções do Node.js permite-lhe especificar o nome da função e o tipo de assinatura como argumentos da linha de comandos ou variáveis de ambiente.

Também pode especificar estes valores no package.json buildfile adicionando um script start com os argumentos da CLI necessários, conforme mostrado no exemplo abaixo.

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

O mesmo pode ser feito através de variáveis de ambiente:

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

Substitua YOUR_FUNCTION_NAME pelo nome do método da sua função e YOUR_SIGNATURE_TYPE (se aplicável) pelo tipo de assinatura da sua função, conforme mostrado em tipos de funções suportados.

Python

O Python Functions Framework permite-lhe especificar o nome da sua função e o tipo de assinatura como argumentos da linha de comandos ou variáveis de ambiente. Os argumentos da linha de comandos têm de ser especificados quando executa a framework.

Ir

O Go Functions Framework usa funcframework.RegisterHTTPFunctionContext para especificar o destino da função e o tipo de assinatura.

Java

O Java Functions Framework aceita dados de configuração de três origens diferentes, na seguinte ordem de prioridade (do mais específico para o menos específico):

  • Argumentos da linha de comandos
  • Buildfiles
  • Variáveis de ambiente

Argumentos da linha de comandos

Maven

Pode especificar a função que quer executar adicionando a seguinte flag da interface de linhas de comando (CLI) aos seus comandos mvn:

-Drun.functionTarget=YOUR_FUNCTION_NAME

Também pode especificar a porta de destino adicionando a seguinte flag da CLI de forma semelhante:

-Drun.port=12345

Gradle

Os flags da CLI do Gradle são quase idênticos aos do Maven. A única alteração que o Gradle faz é trocar o -D inicial em cada flag por um -P, conforme mostrado no seguinte exemplo:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Buildfiles

Também pode especificar a função que quer executar no ficheiro de compilação do seu projeto. Embora o Maven e o Gradle tenham flags da CLI semelhantes, as respetivas cláusulas do ficheiro de compilação diferem significativamente.

Maven

Os ficheiros de compilação do Maven têm o nome pom.xml. Adicione a seguinte cláusula a este ficheiro para especificar uma função de destino:

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

Substitua <functionTarget> pelo nome da classe da sua função. Por exemplo, uma função no pacote functions com o nome da classe HelloCloudFunctions teria um nome da classe de functions.HelloCloudFunctions. Isto é relativo ao ficheiro de compilação principal: pom.xml ou build.gradle.

Gradle

Os ficheiros de compilação do Gradle têm o nome build.gradle. Adicione a seguinte cláusula a este ficheiro para especificar uma função de destino:

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#

Se criar o projeto com dotnet new e um dos modelos especificados anteriormente, o .NET Functions Framework deteta automaticamente a sua função.

Se o seu projeto contiver várias funções, consulte a secção Executar a framework para obter informações sobre como executar uma função específica.

Ruby

O Ruby Functions Framework permite-lhe especificar o nome da sua função e o tipo de assinatura como argumentos da linha de comandos ou variáveis de ambiente. Os argumentos da linha de comandos têm de ser especificados quando executa a framework.

PHP

O PHP Functions Framework permite-lhe especificar variáveis de ambiente como argumentos da linha de comandos.

Também pode especificar estes valores no composer.json buildfile adicionando um script start, conforme mostrado no exemplo seguinte.

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

Substitua YOUR_FUNCTION_NAME pelo nome da sua função e YOUR_SIGNATURE_TYPE (se aplicável; não está incluído no exemplo apresentado aqui).

Execute a função

Use o seguinte comando para executar a sua função com o Functions Framework. Por predefinição, a sua função vai estar acessível em localhost:8080, a menos que especifique explicitamente um valor PORT.

Node.js

npm start

Python

Usando argumentos da linha de comandos:

functions-framework --target=YOUR_FUNCTION_NAME

Usando variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

Substitua YOUR_FUNCTION_NAME pelo nome do método da sua função.

Ir

Primeiro, crie um ficheiro cmd/main.go, conforme descrito no site do Functions Framework for Go.

cd cmd
go build
./cmd

Usando variáveis de ambiente:

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

Use o seguinte comando para executar uma função especificada em pom.xml:

mvn function:run

Use o seguinte comando para executar uma função especificada num argumento da linha de comandos:

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

Use o seguinte comando para executar uma função especificada como uma variável de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

Substitua YOUR_FUNCTION_NAME pelo nome da classe da sua função.

Gradle

Use o seguinte comando para executar uma função especificada em build.gradle:

./gradlew runFunction

Use o seguinte comando para executar uma função especificada num argumento da linha de comandos:

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

Use o seguinte comando para executar uma função especificada como uma variável de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

Substitua YOUR_FUNCTION_NAME pelo nome da classe da sua função.

C#

Use o seguinte comando para executar a sua função quando existir exatamente uma função no projeto .NET atual. Tenha em atenção que esta é a estrutura predefinida para projetos criados com base em modelos.

dotnet run

Se o seu projeto .NET contiver várias funções, use o seguinte comando para executar uma função específica. Substitua YOUR_FUNCTION_CLASSNAME pelo nome da classe da função, incluindo o espaço de nomes.

dotnet run YOUR_FUNCTION_CLASSNAME

Se quiser executar várias funções em simultâneo, tem de executar várias instâncias do Functions Framework. Para evitar conflitos entre instâncias de frameworks em execução, cada instância deve usar um valor de PORT diferente. O comando seguinte mostra como executar uma função com um valor de PORT de 8080.

Usando argumentos da linha de comandos:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Usando variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Usando argumentos da linha de comandos:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Usando variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

Substitua YOUR_FUNCTION_NAME pelo nome do método da sua função.

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

Substitua YOUR_FUNCTION_NAME pelo nome da sua função.

Chame a sua função executada localmente

Os exercícios nesta secção partem do princípio de que configurou uma função em execução localmente em localhost através do Functions Framework.

Pode acionar funções executadas localmente enviando-lhes pedidos HTTP encaminhados através de um processo de publicação local.

Funções HTTP

Quando testa a sua função HTTP a partir do ambiente de desenvolvimento, normalmente, esta fica à escuta de pedidos em localhost:8080. Esta interface só está acessível a partir da máquina ou da VM em que a sua função está a ser executada. Os pedidos enviados a partir de qualquer outro sistema não conseguem aceder à mesma. Por este motivo, tem de emitir o pedido HTTP a partir do mesmo sistema em que a sua função está a ser executada. Nos exemplos seguintes, se a sua função estiver a escutar numa porta diferente de 8080, substitua 8080 no exemplo pelo número da porta da sua função.

Testar funções HTTP com o Cloud Shell

Se estiver a usar o Cloud Shell para criar e testar a sua função, inicie a função localmente na janela do terminal do Cloud Shell e, em seguida, emita o pedido de acionador HTTP a partir de um navegador ou de uma instância curl da seguinte forma:

Navegador

Clique no ícone Botão de pré-visualização da Web na barra de ferramentas do Cloud Shell e escolha porta 8080 ou Alterar porta para escolher uma porta diferente. Esta ação abre uma janela do navegador no sistema correto e envia um pedido GET para a porta indicada.

Curl

Para controlar o formato do seu pedido HTTP ou ver a resposta sem formatação, use curl:

  1. Clique no ícone + na barra de menu do Cloud Shell para abrir uma nova janela do terminal no mesmo sistema em que a sua função está a ser executada.
  2. Nessa janela, execute o comando curl para acionar a sua função. Por exemplo:

    curl localhost:8080
    

Testar funções HTTP no servidor do computador

Se estiver a criar e executar a função no sistema de computador local, primeiro inicie a função localmente e, em seguida, emita o pedido de acionador HTTP a partir de um navegador ou de uma instância curl da seguinte forma:

Navegador

Abra uma nova janela ou separador do navegador e escreva http://localhost:8080 na barra de endereço do navegador. Esta ação abre uma janela do navegador para localhost:8080 no servidor do seu computador para acionar a função.

Curl

Abra uma nova janela de terminal no seu ambiente de trabalho local e, em seguida, execute o comando curl nessa janela para acionar a sua função. Por exemplo:

 curl localhost:8080

Isto executa o comando curl especificado para acionar a sua função e apresenta a resposta não formatada.

Funções orientadas por eventos

Pode enviar eventos de amostra para funções orientadas por eventos usando curl. Os pedidos curl seguintes mostram como enviar exemplos de eventos do Pub/Sub e do Cloud Storage para uma função orientada por eventos em execução em localhost:8080.

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'
    

O que se segue?