Desarrollo de funciones locales

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

La posibilidad de ejecutar tus funciones sin implementarlas puede simplificar las pruebas locales, el cumplimiento de las restricciones de localidad de los datos y las implementaciones multicloud:

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

  • Despliegues multinube: los despliegues de funciones multinube son un patrón establecido para mitigar el riesgo de inactividad en entornos críticos para la fiabilidad. Desplegar funciones en entornos distintos de las funciones de Cloud Run reduce el riesgo de que tu aplicación sufra un tiempo de inactividad no planificado.

Desarrollar 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 el código sin tener que volver a compilar el contenedor de la función. De esta forma, ahorrarás tiempo y te resultará más fácil probar tu función.

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

Functions Framework también se puede ejecutar en cualquier otra plataforma que admita el lenguaje, como tu máquina local, servidores on-premise y Compute Engine.

Instalar dependencias

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

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

Si usas Maven, añade lo siguiente a tu 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, añade 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 más información en la biblioteca del framework de funciones de Java.

C#

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

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

En Ruby, el framework de funciones debe añadirse a las dependencias de tu función para poder desplegarla en Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configurar Functions Framework

Antes de ejecutar una función con Functions Framework, primero debes especificar el tipo y el nombre de la función que quieras ejecutar. Estos atributos se pueden especificar como una marca de la interfaz de línea de comandos (CLI) o como variables de entorno.

Tipos de funciones admitidos

Functions Framework admite los dos tipos de funciones compatibles con Cloud Run Functions. Todos los tiempos de ejecución de idiomas 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 solicitudes HTTP y responden a ellas. Todos los entornos de ejecución
Funciones basadas en eventos cloudevent Formato de evento estándar del sector. Todos los entornos de ejecución

Especificar qué función se va a ejecutar

Antes de ejecutar una función con Functions Framework, primero debe especificar qué función de su código quiere ejecutar. En la mayoría de los idiomas, puedes hacerlo especificando el nombre del método de la función de destino, tal como se muestra en las siguientes tablas. Ten en cuenta que hay excepciones a esta regla para los tiempos de ejecución de Java y .NET.

Instrucciones por idioma

En la siguiente tabla se muestra una lista de las opciones de configuración admitidas en cada idioma.

Node.js

Argumento de CLI Variable de entorno Descripción
--port PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080
--target FUNCTION_TARGET Nombre de la función exporteditada que se va a invocar. Valor predeterminado: function
--signature-type FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (el valor predeterminado) o cloudevent.

Python

Argumento de CLI Variable de entorno Descripción
--port PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080
--target FUNCTION_TARGET Nombre de la función exporteditada que se va a invocar. Valor predeterminado: function
--signature-type FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (el valor predeterminado) o cloudevent.

Go

Variable de entorno Descripción
PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080

Java

Nombre del argumento Variable de entorno Descripción
run.port PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080
run.functionTarget FUNCTION_TARGET Nombre de la función exporteditada que se va a invocar. Valor predeterminado: function

C#

Argumento de CLI Variable de entorno Descripción
--port PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080
--target (o el único argumento) FUNCTION_TARGET El nombre de la clase de la función que se va a invocar. Valor predeterminado: function

Ruby

Argumento de CLI Variable de entorno Descripción
--port PORT Puerto en el que se escuchan las solicitudes. Valor predeterminado: 8080
--target FUNCTION_TARGET Nombre de la función exporteditada que se va a invocar. Valor predeterminado: function

PHP

Variable de entorno Descripción
FUNCTION_TARGET Nombre de la función que se va a invocar. Valor predeterminado: function
FUNCTION_SIGNATURE_TYPE El tipo de firma que usa tu función. Puede ser http (el valor predeterminado) o cloudevent.

Sigue estas instrucciones para configurar y ejecutar Functions Framework:

Node.js

El framework de funciones de 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 puede especificar estos valores en el archivo de compilación package.json añadiendo una secuencia de comandos start con los argumentos de la CLI necesarios, como se muestra en el ejemplo siguiente.

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

También se puede hacer lo mismo con las variables de entorno:

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

Sustituye YOUR_FUNCTION_NAME por el nombre del método de tu función y YOUR_SIGNATURE_TYPE (si procede) por el tipo de firma de tu función, tal como se muestra en los tipos de funciones admitidos.

Python

Python Functions Framework 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. Los argumentos de línea de comandos deben especificarse al ejecutar el framework.

Go

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

Java

Java Functions Framework acepta datos de configuración de tres fuentes diferentes, en el siguiente orden de prioridad (de la más específica a la menos específica):

  • Argumentos de línea de comandos
  • Buildfiles
  • Variables de entorno

Argumentos de línea de comandos

Maven

Puedes especificar la función que quieras ejecutar añadiendo la siguiente marca de interfaz de línea de comandos (CLI) a tus comandos de mvn:

-Drun.functionTarget=YOUR_FUNCTION_NAME

También puede especificar el puerto de destino añadiendo la siguiente marca de CLI de forma similar:

-Drun.port=12345

Gradle

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

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Buildfiles

También puedes especificar la función que quieras ejecutar en el archivo de compilación de tu proyecto. Aunque Maven y Gradle tienen marcas de CLI similares, sus cláusulas de archivo de compilación difieren significativamente.

Maven

Los archivos de compilación de Maven se denominan pom.xml. Añade 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>

Sustituye <functionTarget> por el nombre de la clase de tu función. Por ejemplo, una función del paquete functions con el nombre de clase HelloCloudFunctions tendría el nombre de clase functions.HelloCloudFunctions. Es relativa al archivo de compilación principal: pom.xml o build.gradle.

Gradle

Los archivos de compilación de Gradle se llaman build.gradle. Añade 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 anteriormente, .NET Functions Framework detectará automáticamente tu función.

Si tu proyecto contiene varias funciones, consulta la sección Ejecutar el framework para obtener información sobre cómo ejecutar una función específica.

Ruby

Ruby Functions Framework 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. Los argumentos de línea de comandos deben especificarse al ejecutar el framework.

PHP

El framework de funciones de PHP te permite especificar variables de entorno como argumentos de línea de comandos.

También puede especificar estos valores en el composer.json archivo de compilación añadiendo 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"
].
}

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

Ejecutar la función

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

Node.js

npm start

Python

Usar argumentos de línea de comandos:

functions-framework --target=YOUR_FUNCTION_NAME

Usar variables de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

Sustituye YOUR_FUNCTION_NAME por el nombre del método de tu función.

Go

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

cd cmd
go build
./cmd

Usar 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 variable de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

Sustituye YOUR_FUNCTION_NAME por el nombre de clase de tu 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 variable de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

Sustituye YOUR_FUNCTION_NAME por el nombre de clase de tu función.

C#

Usa el siguiente comando para ejecutar tu función cuando haya exactamente una función en el proyecto .NET actual. Ten en cuenta que esta es la estructura predeterminada de los proyectos creados con plantillas.

dotnet run

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

dotnet run YOUR_FUNCTION_CLASSNAME

Si quieres ejecutar varias funciones simultáneamente, tendrás que ejecutar varias instancias de Functions Framework. Para evitar conflictos entre las instancias del framework en ejecución, cada instancia debe usar un valor PORT diferente. El siguiente comando muestra cómo ejecutar una función con un valor PORT de 8080.

Usar argumentos de línea de comandos:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Usar variables de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Usar argumentos de línea de comandos:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Usar variables de entorno:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

Sustituye YOUR_FUNCTION_NAME por el nombre del método de tu función.

PHP

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

Sustituye YOUR_FUNCTION_NAME por el nombre de tu función.

Llamar a la función que se está ejecutando localmente

En los ejercicios de esta sección se presupone que has configurado una función que se ejecuta localmente en localhost con Functions Framework.

Puedes activar funciones que se ejecutan localmente enviándoles solicitudes HTTP enrutadas mediante un proceso de servicio local.

Funciones HTTP

Cuando pruebas tu función HTTP desde tu entorno de desarrollo, normalmente escucha las solicitudes en localhost:8080. Solo se puede acceder a esta interfaz desde la máquina o la VM en la que se ejecuta tu función. Las solicitudes enviadas desde cualquier otro sistema no pueden acceder a ella. Por este motivo, debes enviar la solicitud HTTP desde el mismo sistema en el que se ejecuta tu función. En los ejemplos siguientes, si tu función está escuchando en un puerto que no sea 8080, sustituye 8080 por el número de puerto de tu función.

Probar funciones HTTP con Cloud Shell

Si usas Cloud Shell para compilar y probar tu función, inicia la función de forma local en la ventana de terminal de Cloud Shell y, a continuación, envía la solicitud de activación HTTP desde un navegador o una instancia de curl de la siguiente manera:

Navegador

Haz clic en el icono Botón Vista previa web de la barra de herramientas de Cloud Shell y elige puerto 8080 o Cambiar puerto para seleccionar otro puerto. Se abrirá una ventana del navegador en el sistema correcto y se enviará 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 icono + de la barra de menú de Cloud Shell para abrir una nueva ventana de terminal en el mismo sistema en el que se ejecuta tu función.
  2. En esa ventana, ejecuta el comando curl para activar la función. Por ejemplo:

    curl localhost:8080
    

Probar funciones HTTP en el servidor de tu ordenador

Si vas a compilar y ejecutar tu función en tu sistema de escritorio local, primero inicia la función localmente y, a continuación, envía la solicitud de activación HTTP desde un navegador o una instancia de 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. 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 tu escritorio local y, a continuación, ejecuta el comando curl en esa ventana para activar tu función. Por ejemplo:

 curl localhost:8080

De esta forma, se ejecuta el comando curl especificado para activar la función y se muestra la respuesta sin formato.

Funciones basadas en eventos

Puedes enviar eventos de muestra a funciones basadas en eventos mediante curl. Las siguientes solicitudes curl muestran cómo enviar eventos de ejemplo de Pub/Sub y Cloud Storage a una función basada en eventos 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"
      }'
    

Siguientes pasos