Desenvolvimento de funções locais

O Cloud Run functions é compatível com vários métodos de execução de funções fora do ambiente de implantação de destino. Isso é especialmente útil para o desenvolvimento iterativo e em situações em que você quer testar a função antes da implantação.

A capacidade de executar suas funções sem implantá-las pode simplificar os testes locais, a conformidade com as restrições de localidade de dados e as implantações de várias nuvens:

  • Restrições de localidade de dados: teste a função localmente sem acessar dados de produção para evitar a violação das regras de localidade de dados da sua organização.

  • Implantações em várias nuvens: as implantações de funções em várias nuvens são um padrão estabelecido para reduzir o risco de inatividade em ambientes críticos de confiabilidade. A implantação de funções em ambientes diferentes do Cloud Run functions reduz o risco de seu aplicativo sofrer tempo de inatividade não planejado.

Desenvolver funções localmente usando o Functions Framework

É possível desenvolver e testar funções localmente usando o Functions Framework. O desenvolvimento de uma função localmente pode ajudar a testar o código sem precisar recriar o contêiner de função. Isso pode economizar tempo e facilitar o teste da função.

O Cloud Run usa as bibliotecas de código aberto Functions Framework para unir as funções implantadas em um aplicativo HTTP persistente.

O Functions Framework também pode ser executado em qualquer outra plataforma compatível com a própria linguagem, incluindo sua máquina local, servidores no local e o Compute Engine.

Instalar dependências

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

Node.js

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

Python

pip3 install functions-framework

Go

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

Java

Maven

Se você estiver usando o Maven, adicione o seguinte ao arquivo 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 você estiver usando o Gradle, adicione o seguinte ao arquivo 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 do Java Functions Framework para mais informações.

C#

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

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

No Ruby, o Functions Framework precisa ser adicionado às dependências da função para implantá-lo no Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configurar o Functions Framework

Antes de executar uma função usando o Functions Framework, primeiro é necessário especificar o tipo e o nome da função que você quer executar. Esses atributos podem ser especificados como sinalizações da interface de linha de comando (CLI) ou como variáveis de ambiente.

Tipos de função compatíveis

O Functions Framework é compatível com os dois tipos de funções do Cloud Run functions. Todos os ambientes de execução de linguagem são compatíveis com os tipos de assinatura http e cloudevent.

Tipo de função Tipo de assinatura Descrição Ambientes de execução compatíveis
Funções acionadas por HTTP http Funções que recebem e respondem a solicitações HTTP. Todos os ambientes de execução
Funções do CloudEvent cloudevent Formato de evento padrão do setor. Todos os ambientes de execução

Especificar qual função será executada

Antes de executar uma função com o Functions Framework, primeiro é preciso especificar qual função do código será executada. Para a maioria das linguagens, é possível especificar o nome do método da função de destino, conforme mostrado nas tabelas abaixo. Há exceções a essa regra para os ambientes de execução Java e .NET.

Instruções por linguagem

Consulte a tabela a seguir para conferir uma lista de opções de configuração compatíveis com cada linguagem.

Node.js

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para detectar solicitações. Padrão: 8080.
--target FUNCTION_TARGET O nome da função export que será invocada. (Padrão: function)
--signature-type FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela função. Pode ser http (padrão) ou cloudevent.

Python

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para detectar solicitações. Padrão: 8080.
--target FUNCTION_TARGET O nome da função export que será invocada. (Padrão: function)
--signature-type FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela função. Pode ser http (padrão) ou cloudevent.

Go

Variável de ambiente Descrição
PORT A porta para detectar solicitações. Padrão: 8080.

Java

Nome do argumento Variável de ambiente Descrição
run.port PORT A porta para detectar solicitações. Padrão: 8080.
run.functionTarget FUNCTION_TARGET O nome da função export que será invocada. (Padrão: function)

C#

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para detectar solicitações. Padrão: 8080.
--target (ou apenas argumento) FUNCTION_TARGET O classname da função a ser invocada. (Padrão: function)

Ruby

Argumento da CLI Variável de ambiente Descrição
--port PORT A porta para detectar solicitações. Padrão: 8080.
--target FUNCTION_TARGET O nome da função export que será invocada. (Padrão: function)

PHP

Variável de ambiente Descrição
FUNCTION_TARGET O nome da função que será invocada. (Padrão: function)
FUNCTION_SIGNATURE_TYPE O tipo de assinatura usado pela função. Pode ser http (padrão) ou cloudevent.

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

Node.js

Com o Functions Framework para Node.js, é possível especificar o tipo de assinatura e de nome da função como argumentos de linha de comando ou variáveis de ambiente.

Também é possível especificar esses valores no arquivo de build package.json adicionando um script start com os argumentos da CLI necessários, como mostrado no exemplo abaixo.

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

Faça o mesmo usando 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 função e YOUR_SIGNATURE_TYPE (se aplicável) pelo tipo de assinatura da função, conforme mostrado em tipos de função aceitos.

Python

Com o Functions Framework para Python, é possível especificar o tipo de assinatura e de nome da função como argumentos de linha de comando ou variáveis de ambiente. Os argumentos de linha de comando precisam ser especificados ao executar o framework.

Go

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

Java

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

  • Argumentos de linha de comando
  • Arquivos de build
  • Variáveis de ambiente

Argumentos de linha de comando

Maven

É possível especificar a função que você quer executar adicionando a seguinte sinalização de interface de linha de comando (CLI, na sigla em inglês) aos comandos mvn:

-Drun.functionTarget=YOUR_FUNCTION_NAME

Também é possível especificar a porta de destino adicionando a seguinte sinalização CLI de maneira semelhante:

-Drun.port=12345

Gradle

As sinalizações da CLI do Gradle são quase idênticas às do Maven. A única mudança que o Gradle faz é trocar o -D inicial em cada sinalização por um -P, conforme mostrado no exemplo abaixo:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Arquivos de build

Também é possível especificar a função que você quer executar no arquivo de build do projeto. Embora o Maven e o Gradle tenham sinalizações de CLI semelhantes, as cláusulas de arquivo de build são significativamente diferentes.

Maven

Os arquivos de build do Maven são chamados pom.xml. Adicione a seguinte cláusula a esse arquivo 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 de classe da função. Por exemplo, uma função no pacote functions com o nome de classe HelloCloudFunctions teria um nome de classe functions.HelloCloudFunctions. Ele é relativo ao arquivo de build pai pom.xml ou build.gradle.

Gradle

Os arquivos de build do Gradle são chamados de build.gradle. Adicione a cláusula a seguir a esse arquivo 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 você criar um projeto usando dotnet new e um dos modelos especificados anteriormente, o Functions Framework para .NET vai detectar automaticamente a função.

Se o projeto tiver várias funções, consulte a seção Como executar o framework para informações sobre como executar uma função específica.

Ruby

Com o Functions Framework para Ruby, é possível especificar o tipo de assinatura e de nome da função como argumentos de linha de comando ou variáveis de ambiente. Os argumentos de linha de comando precisam ser especificados ao executar o framework.

PHP

Com o framework de funções do PHP, você pode especificar variáveis de ambiente como argumentos de linha de comando.

Também é possível especificar esses valores no arquivo de build composer.json adicionando um script start, como mostrado no exemplo abaixo.

"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 função e YOUR_SIGNATURE_TYPE (se aplicável, não está incluído no exemplo mostrado aqui).

Executar a função

Use o comando a seguir para executar a função com o Functions Framework. Por padrão, a função estará acessível em localhost:8080, a menos que você especifique explicitamente um valor PORT.

Node.js

npm start

Python

Como usar argumentos de linha de comando:

functions-framework --target=YOUR_FUNCTION_NAME

Como usar variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

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

Go

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

cd cmd
go build
./cmd

Como usar 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 em um argumento da linha de comando:

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 de classe da 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 em um argumento da linha de comando:

./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 de classe da função.

C#

Use o seguinte comando para executar a função quando exatamente uma função estiver presente no projeto atual do .NET. Essa é a estrutura padrão para projetos criados por modelos.

dotnet run

Caso o projeto .NET contenha várias funções, use o seguinte comando para executar uma função específica. Substitua YOUR_FUNCTION_CLASSNAME pelo nome de classe da função, incluindo o namespace.

dotnet run YOUR_FUNCTION_CLASSNAME

Se você quiser executar várias funções simultaneamente, precisará executar várias instâncias do Functions Framework. Para evitar conflitos entre instâncias de framework em execução, cada instância precisa usar um valor PORT diferente. O comando a seguir mostra como executar uma função com um valor PORT de 8080.

Como usar argumentos de linha de comando:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Como usar variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Como usar argumentos de linha de comando:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Como usar variáveis de ambiente:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

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

PHP

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

Substitua YOUR_FUNCTION_NAME pelo nome da função.

Chamar a função em execução localmente

Os exercícios desta seção pressupõem que você configurou uma função executada localmente em localhost usando o Functions Framework.

É possível acionar funções em execução no local enviando a elas solicitações HTTP encaminhadas usando um processo de exibição local.

Funções HTTP

Quando você testa a função HTTP no ambiente de desenvolvimento, ela normalmente detecta solicitações em localhost:8080. Essa interface só pode ser acessada por meio da máquina ou VM em que a função está sendo executada. As solicitações enviadas de outros sistemas não conseguem acessá-la. Por esse motivo, é necessário emitir a solicitação HTTP no mesmo sistema em que a função está sendo executada. Nos exemplos a seguir, se a função estiver fazendo detecções em uma porta diferente de 8080, substitua 8080 no exemplo pelo número da porta da função.

Como testar funções HTTP com o Cloud Shell

Se você estiver usando o Cloud Shell para criar e testar sua função, inicie-a localmente na janela do terminal do Cloud Shell e emita a solicitação de gatilho HTTP de um navegador ou de uma instância curl da seguinte maneira:

Navegador

Clique no ícone Botão de visualização da Web na barra de ferramentas do Cloud Shell e escolha porta 8080 ou Alterar porta para escolher uma porta diferente. Isso abre uma janela do navegador no sistema correto e emite uma solicitação GET para a porta indicada.

Curl

Para controlar o formato da solicitação HTTP ou ver a resposta não formatada, use curl:

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

    curl localhost:8080
    

Como testar funções HTTP no servidor da área de trabalho

Se você estiver criando e executando a função no sistema da área de trabalho local, primeiro inicie-a localmente e, em seguida, emita a solicitação de gatilho HTTP de um navegador ou de uma instância curl da seguinte maneira:

Navegador

Abra uma nova janela ou guia do navegador e digite http://localhost:8080 na barra de endereço. Isso abre uma janela do navegador para localhost:8080 no servidor da área de trabalho a fim de acionar a função.

Curl

Abra uma nova janela de terminal na área de trabalho local e execute o comando curl nela para acionar a função. Exemplo:

 curl localhost:8080

Isso executa o comando curl especificado para acionar a função e exibe a resposta não formatada.

Funções do CloudEvent

É possível enviar eventos de amostra para Funções do CloudEvent usando curl. As seguintes solicitações curl mostram como enviar eventos de amostra do Pub/Sub e do Cloud Storage para uma função do CloudEvent 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"
      }'