Desarrollo de funciones locales

Cloud Run Functions admite varios métodos para ejecutar las funciones fuera del entorno de implementación de destino. Esto es particularmente útil para el desarrollo iterativo y situaciones en las que quieres probar tu función antes de implementarla.

La capacidad de ejecutar las funciones sin implementarlas puede simplificar las pruebas locales, el cumplimiento de las restricciones de localidad de datos y las implementaciones de múltiples nubes:

  • Restricciones de localidad de datos: Prueba tu función de forma local sin acceder a los datos de producción para evitar incumplir las reglas de localidad de datos de tu organización.

  • Implementaciones en múltiples nubes: Las implementaciones de funciones en múltiples nubes tienen un patrón establecido para mitigar el riesgo de tiempo de inactividad en entornos críticos para la confiabilidad. Implementar funciones en entornos que no sean de Cloud Run reduce el riesgo de que tu aplicación experimente un tiempo de inactividad no planificado.

Desarrolla funciones de forma local con Functions Framework

Puedes desarrollar y probar funciones de forma local con Functions Framework. Desarrollar una función de forma local puede ayudarte a probar tu código sin tener que volver a compilar el contenedor de la función. Esto puede ahorrar tiempo y facilitar la prueba de tu función.

Cloud Run usa las bibliotecas de código abierto de Functions Framework para unir tus funciones implementadas en una aplicación HTTP persistente.

Functions Framework también puede ejecutarse en cualquier otra plataforma que admita el lenguaje en sí, como tu máquina local, servidores locales y Compute Engine.

Instala dependencias

En el directorio de la función, instala la biblioteca de Functions Framework para tu lenguaje:

Node.js

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

Python

pip3 install functions-framework

Comienza a usarlo

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

Java

Maven

Si usas Maven, agrega lo siguiente al archivo pom.xml:

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

Gradle

Si usas Gradle, agrega lo siguiente al archivo 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'
}

Consulta la biblioteca de Functions Framework para Java a fin de obtener más información.

C#

Los siguientes comandos usan plantillas .NET para crear una base de código nueva de función .NET con la biblioteca de Functions Framework de.NET como una dependencia:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

En Ruby, Functions Framework debe agregarse a las dependencias de la función para implementarla en Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configura Functions Framework

Debes especificar el tipo y el nombre de la función que desees ejecutar antes de ejecutarla mediante Functions Framework. Estos atributos se pueden especificar como marcas de la interfaz de línea de comandos (CLI) o como variables de entorno.

Tipos de funciones compatibles

Functions Framework admite ambos tipos de funciones compatibles con Cloud Run Functions. Todos los entornos de ejecución de lenguajes admiten los tipos de firma http y cloudevent.

Tipo de función Tipo de firma Descripción Entornos de ejecución compatibles
Funciones activadas por HTTP http Funciones que reciben y responden solicitudes HTTP Todos los entornos de ejecución
Funciones de CloudEvent cloudevent Formato de evento estándar de la industria Todos los entornos de ejecución

Especifica qué función se ejecutará

Debes especificar qué función dentro de tu código se debe ejecutar antes de ejecutar una función con Functions Framework. Para la mayoría de los lenguajes, puedes hacerlo si especificas el nombre del método de la función de destino como se muestra en las tablas a continuación. Ten en cuenta que existen excepciones a esta regla para los entornos de ejecución de Java y .NET.

Instrucciones por idioma

Consulta la siguiente tabla para obtener una lista de las opciones de configuración compatibles con cada lenguaje.

Node.js

Argumento de la CLI Variable de entorno Descripción
--port PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)
--target FUNCTION_TARGET El nombre de la función export que se invocará (Predeterminado: function)
--signature-type FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (predeterminado) o cloudevent.

Python

Argumento de la CLI Variable de entorno Descripción
--port PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)
--target FUNCTION_TARGET El nombre de la función export que se invocará (Predeterminado: function)
--signature-type FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (predeterminado) o cloudevent.

Go

Variable de entorno Descripción
PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)

Java

Nombre del argumento Variable de entorno Descripción
run.port PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)
run.functionTarget FUNCTION_TARGET El nombre de la función export que se invocará (Predeterminado: function)

C#

Argumento de la CLI Variable de entorno Descripción
--port PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)
--target (o solo el argumento) FUNCTION_TARGET El classname de la función que se invocará (Predeterminado: function)

Ruby

Argumento de la CLI Variable de entorno Descripción
--port PORT El puerto en el que se deben escuchar las solicitudes (Predeterminado: 8080)
--target FUNCTION_TARGET El nombre de la función export que se invocará (Predeterminado: function)

PHP

Variable de entorno Descripción
FUNCTION_TARGET El nombre de la función que se invocará (Predeterminado: function)
FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (predeterminado) o cloudevent.

Sigue estas instrucciones para configurar y ejecutar Functions Framework:

Node.js

Functions Framework para Node.js te permite especificar el nombre y el tipo de firma de tu función como argumentos de línea de comandos o variables de entorno.

También puedes especificar estos valores en el archivo de compilación package.json si agregas una secuencia de comandos start con los argumentos de la CLI requeridos, como se muestra en el siguiente ejemplo.

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

Lo mismo se puede hacer con las variables de entorno:

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

Reemplaza YOUR_FUNCTION_NAME por el nombre del método y YOUR_SIGNATURE_TYPE por el tipo de firma de la función, si corresponde, como se muestra en los tipos de funciones admitidos.

Python

Functions Framework para Python te permite especificar el nombre y el tipo de firma de la función como argumentos de línea de comandos o variables de entorno. Los argumentos de línea de comandos deben especificarse cuando ejecutas el framework.

Go

Functions Framework de Go usa funcframework.RegisterHTTPFunctionContext para especificar el destino y el tipo de firma de la función.

Java

Functions Framework para Java acepta datos de configuración de tres fuentes diferentes en el siguiente orden de prioridad (del más específico al menos específico):

  • Argumentos de la línea de comandos
  • Archivos de compilación
  • Variables de entorno

Argumentos de la línea de comandos

Maven

Para especificar la función que deseas ejecutar, agrega la siguiente marca de la interfaz de línea de comandos (CLI) a los comandos mvn:

-Drun.functionTarget=YOUR_FUNCTION_NAME

También puedes especificar el puerto de destino si agregas la siguiente marca de la CLI de forma similar:

-Drun.port=12345

Gradle

Los marcas de la CLI de Gradle son casi idénticas a las de Maven. El único cambio que realiza Gradle es intercambiar la -D inicial en cada marca por una -P, como se muestra en el siguiente ejemplo:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Archivos de compilación

También puedes especificar la función que desees ejecutar en el archivo de compilación del proyecto. Si bien Maven y Gradle tienen marcas similares de la CLI, sus cláusulas de archivo de compilación difieren de manera significativa.

Maven

Los archivos de compilación de Maven se denominan pom.xml. Agrega la siguiente cláusula a este archivo para especificar una función 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>

Reemplaza <functionTarget> por el nombre de clase de tu función. Por ejemplo, una función en el paquete functions con el nombre de clase HelloCloudFunctions tendría un nombre de clase functions.HelloCloudFunctions. Esto está relacionado con el archivo de compilación superior, ya sea pom.xml o build.gradle.

Gradle

Los archivos de compilación de Gradle se denominan build.gradle. Agrega la siguiente cláusula a este archivo para especificar una función 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#

Si creas tu proyecto con dotnet new y una de las plantillas especificadas antes, Functions Framework para .NET detectará de forma automática la función.

Si tu proyecto contiene varias funciones, consulta la sección Ejecuta el framework a fin de obtener información para ejecutar una función específica.

Ruby

Functions Framework para Ruby te permite especificar el nombre y el tipo de firma de la función como argumentos de línea de comandos o variables de entorno. Los argumentos de línea de comandos deben especificarse cuando ejecutas el framework.

PHP

Functions Framework de PHP te permite especificar variables de entorno como argumentos de línea de comandos.

También puedes especificar estos valores en el archivo de compilación composer.json si agregas una secuencia de comandos start como se muestra en el siguiente ejemplo.

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

Reemplaza YOUR_FUNCTION_NAME por el nombre de tu función y YOUR_SIGNATURE_TYPE (si corresponde; no se incluye en el ejemplo que se muestra aquí).

Ejecuta tu función

Usa el siguiente comando para ejecutar la función con Functions Framework. De forma predeterminada, se podrá acceder a la función en localhost:8080, a menos que especifiques de forma explícita un valor PORT.

Node.js

npm start

Python

Usa los argumentos de línea de comandos:

functions-framework --target=YOUR_FUNCTION_NAME

Usa variables de entorno

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

Reemplaza YOUR_FUNCTION_NAME por el nombre del método de la función.

Go

Primero, crea un archivo cmd/main.go como se describe en el sitio Functions Framework para Go.

cd cmd
go build
./cmd

Usa variables de entorno

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

Usa el siguiente comando para ejecutar una función especificada en pom.xml:

mvn function:run

Usa el siguiente comando para ejecutar una función especificada en un argumento de línea de comandos:

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

Usa el siguiente comando para ejecutar una función especificada como una variable de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

Reemplaza YOUR_FUNCTION_NAME por el nombre de clase de la función.

Gradle

Usa el siguiente comando para ejecutar una función especificada en build.gradle:

./gradlew runFunction

Usa el siguiente comando para ejecutar una función especificada en un argumento de línea de comandos:

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

Usa el siguiente comando para ejecutar una función especificada como una variable de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

Reemplaza YOUR_FUNCTION_NAME por el nombre de clase de la función.

C#

Usa el siguiente comando para ejecutar la función cuando esté presente solo una función en el proyecto .NET actual Ten en cuenta que esta es la estructura predeterminada para los proyectos creados con plantillas.

dotnet run

Si tu proyecto .NET contiene varias funciones, usa el siguiente comando para ejecutar una función específica. Reemplaza YOUR_FUNCTION_CLASSNAME por el nombre de clase de la función, incluido el espacio de nombres.

dotnet run YOUR_FUNCTION_CLASSNAME

Si deseas ejecutar varias funciones de forma simultánea, deberás ejecutar varias instancias de Functions Framework. Para evitar conflictos entre las instancias de framework en ejecución, cada instancia debe usar un valor PORT diferente. En el siguiente comando, se muestra cómo ejecutar una función con un valor PORT de 8080.

Usa los argumentos de línea de comandos:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Usa variables de entorno

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Usa los argumentos de línea de comandos:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Usa variables de entorno

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

Reemplaza YOUR_FUNCTION_NAME por el nombre del método de la función.

PHP

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

Reemplaza YOUR_FUNCTION_NAME por el nombre de la función.

Llama a tu función que se ejecuta de forma local

En los ejercicios de esta sección, se supone que configuraste una función que se ejecuta de forma local en localhost con Functions Framework.

Puedes activar funciones que se ejecuten de forma local si envías solicitudes HTTP enrutadas a través de un proceso de entrega local.

Funciones de HTTP

Cuando pruebas tu función de HTTP desde tu entorno de desarrollo, esta suele escuchar solicitudes en localhost:8080. Solo se puede acceder a esta interfaz desde la máquina o VM en la que se ejecuta tu función; las solicitudes enviadas desde cualquier otro sistema no pueden acceder a la interfaz. Por este motivo, debes emitir la solicitud HTTP desde el mismo sistema en el que se ejecuta tu función. En los siguientes ejemplos, si tu función escucha en un puerto distinto de 8080, reemplaza 8080 en el ejemplo por el número de puerto de tu función.

Prueba funciones de HTTP con Cloud Shell

Si usas Cloud Shell para compilar y probar tu función, inicia tu función de forma local en la ventana de la terminal de Cloud Shell y, luego, emite la solicitud del activador HTTP desde un navegador o una instancia curl de la siguiente manera:

Navegador

Haz clic en el ícono Botón Vista previa en la Web en la barra de herramientas de Cloud Shell y elige puerto 8080 o Cambiar puerto para elegir otro. De este modo, se abrirá una ventana del navegador en el sistema correcto y se emitirá una solicitud GET al puerto indicado.

Curl

Para controlar el formato de tu solicitud HTTP o ver la respuesta sin formato, usa curl:

  1. Haz clic en el ícono + en la barra de menú de Cloud Shell para abrir una ventana de terminal nueva en el mismo sistema en el que se ejecuta tu función.
  2. Desde esa ventana, ejecuta el comando curl para activar la función. Por ejemplo:

    curl localhost:8080
    

Prueba funciones de HTTP en tu servidor de escritorio

Si compilas y ejecutas tu función en tu sistema de escritorio local, primero iníciala de forma local y, luego, emite la solicitud del activador HTTP desde un navegador o una instancia curl de la siguiente manera:

Navegador

Abre una nueva ventana o pestaña del navegador y escribe http://localhost:8080 en la barra de direcciones del navegador. De este modo, se abrirá una ventana del navegador en localhost:8080 en tu servidor de escritorio para activar la función.

Curl

Abre una nueva ventana de terminal en el escritorio local y, luego, ejecuta el comando curl en esa ventana para activar la función. Por ejemplo:

 curl localhost:8080

Esto ejecuta el comando curl especificado para activar la función y muestra la respuesta sin formato.

Funciones de CloudEvent

Puedes enviar eventos de muestra a las funciones de CloudEvent mediante curl. En las siguientes solicitudes curl, se muestra cómo enviar eventos de muestra de Pub/Sub y Cloud Storage a una función de CloudEvent que se ejecuta en 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"
      }'