Tarea de Cloud Function

La tarea de Cloud Function te permite configurar y ejecutar funciones de Cloud Run desde tu integración. Las funciones de Cloud Run representan la próxima evolución de Cloud Functions, ya que ofrecen un modelo de programación controlado por eventos con control y escalabilidad mejorados, aprovechando la plataforma sin servidores de Cloud Run. Las funciones de Cloud Run proporcionan una solución única sin servidores para todos los tipos de cargas de trabajo.

La tarea de Cloud Function admite las siguientes versiones de funciones de Cloud Run:

Para obtener información detallada sobre las diferencias entre las versiones de las funciones de Cloud Run, consulta la guía de comparación de Cloud Functions.

Antes de comenzar

Asegúrate de realizar las siguientes tareas en tu proyecto de Google Cloud antes de configurar la tarea de Cloud Function.

  1. Para conectarte a Cloud Function, asegúrate de haber creado un perfil de OAuth 2.0 o adjuntado una cuenta de servicio administrada por el usuario a tu integración:
    • Si tu integración tiene una cuenta de servicio adjunta, asigna el rol de IAM Invocador de Cloud Functions a esa cuenta de servicio.

      Para obtener información sobre cómo otorgar roles a una cuenta de servicio, consulta Administra el acceso a las cuentas de servicio.

    • La tarea de Cloud Function solo permite perfiles de autenticación de tipo Token de ID de OIDC de Google. Crea un perfil de autenticación de tipo Token de ID de OIDC de Google a través de la cuenta de servicio con el rol de IAM de invocador de Cloud Functions asignado. Si tu tarea de Cloud Function no requiere autenticación, el campo Perfil de autenticación en el panel de configuración de las tareas se puede dejar en blanco.

    Si tu integración tiene configurados un perfil de ID de OIDC y una cuenta de servicio administrada por el usuario, el perfil de ID de OIDC se usa para la autenticación de forma predeterminada. Si no se configuran el perfil de ID de OIDC ni la cuenta de servicio administrada por el usuario, la cuenta de servicio predeterminada (service-PROJECT_NUMBER@gcp-sa-integrations.iam.gserviceaccount.com) se usa para llamar a la tarea de Cloud Function.

  2. Asegúrate de que los Controles del servicio de VPC no estén configurados para Application Integration en tu Google Cloud proyecto.

Configura la tarea de la Cloud Function

Para configurar la tarea de Cloud Function en tu integración, realiza los siguientes pasos:

  1. En el menú de navegación, haz clic en Integraciones.

    Se abrirá la lista de integraciones disponibles en la IU de Application Integration.

  2. Selecciona una integración existente o haz clic en Crear integración.

    Si creas una integración nueva, ingresa un nombre y una descripción en el diálogo de creación y haz clic en Crear.

  3. En el menú desplegable Tareas, haz clic en Cloud Function para colocarlo en el editor de integración.
  4. Haz clic en el elemento Cloud Function en el diseñador para abrir el panel de configuración y, luego, haz clic en Configura Cloud Function.
  5. Si se te solicita que otorgues permisos a la cuenta de servicio, haz clic en Otorgar.

    Application Integration otorga automáticamente los permisos necesarios a la cuenta de servicio.

  6. En el panel Configuración de Cloud Function, selecciona una de las siguientes opciones:
    • Vincular función existente: Selecciona esta opción para asociar una función existente con tu integración. Puedes vincular Cloud Functions (1ª gen.) y Cloud Functions creadas con la API de Cloud Functions v2 desde tu integración.
      • En el campo URL del activador de Cloud Function, ingresa la URL del activador de la función existente.

        La URL debe seguir uno de los siguientes formatos:

        # For Cloud Functions (1st gen)
        https://REGION_NAME-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
        # For Cloud Run functions created using the Cloud Functions v2 API
        https://FUNCTION_NAME-PROJECT_ID.REGION_NAME.run.app

    • Crear función nueva: Selecciona esta opción para crear una función nueva para la integración.
      1. En el campo Nombre de la función, ingresa un nombre único para las nuevas funciones de Cloud Run.
      2. En el menú desplegable Región, selecciona la región en la que se implementa la función de Cloud Run.
      3. En el menú desplegable Versión de la función, selecciona la versión deseada de la función de Cloud Run:
        • Cloud Functions (1ª gen.): Esta es la versión heredada de las funciones de Cloud Run, antes conocida como Cloud Functions (1ª gen.), que usa el formato de extremo .cloudfunctions.net.
        • Cloud Functions (última gen.): Esta es la versión más reciente de las funciones de Cloud Run, creada con la API de Cloud Functions v2. Compilada en Cloud Run y Eventarc, admite tiempos de espera de solicitudes extendidos (hasta 60 minutos), ofrece mayor simultaneidad y usa los formatos de extremo .cloudfunctions.net y .run.app.
        • Para obtener más información sobre las diferencias entre las dos versiones, consulta Compara Cloud Functions.
  7. Haz clic en Guardar.
  8. Configurar una tarea de Cloud Function en Application Integration crea una función básica de Cloud Run activada por HTTP- triggered en tu proyecto de Google Cloud.

Plantilla de Cloud Functions

En los siguientes ejemplos, se muestra cómo usar la tarea de Cloud Function en tu integración para diferentes lenguajes.

Python

Cuando configures la Cloud Function con una función de Cloud Run existente, asegúrate de que los archivos de origen main.py, task.py y requirements.txt de la función tengan el siguiente formato:

task.py

      # Sample Code:
      # print(event.get('task_string_key'))
      # event.set('task_int_array_key', [456, 789]);
      # event.log('some logging')

      def run(event):
        """Actual cloud function custom logic.
        Args:
          event : event object in main.py that contains all parameters.
        """
        return
    

main.py

      """Un-editable platform wrapper which invokes user code."""
    import traceback

    from flask import json
    from flask import jsonify
    from task import run

    VALUE_NAME = [
        'stringValue', 'intValue', 'doubleValue', 'booleanValue', 'protoValue'
    ]
    ARRAY_VALUE_NAME = {
        'stringArray': 'stringValues',
        'intArray': 'intValues',
        'doubleArray': 'doubleValues',
        'booleanArray': 'booleanValues',
        'protoArray': 'protoValues'
    }
    VALUE_TYPE_URL = 'type.googleapis.com/google.protobuf.Value'
    CLOUD_FUNCTION_EXCEPTION_KEY = 'CloudFunctionException'
    CLOUD_FUNCTION_LOGGING_KEY = 'CloudFunctionLogging'


    class _Event(object):
      """Event object."""

      def __init__(self, json_payload):
        self._event_params = json_payload.get('eventParameters', dict())
        self._task_params = json_payload.get('taskParameters', dict())
        self._log = []
        print('Event param is ' + str(self._event_params))
        print('Task param is ' + str(self._task_params))

      def set(self, key, value):
        """Set the event parameters key-value.

        Args:
          key: parameter key.
          value: parameter value.
        """
        new_param = self._create_param(key, value)
        param = self._get_param_by_key(key)
        if param is None:
          if 'parameters' not in self._event_params:
            self._event_params['parameters'] = []
          self._event_params['parameters'].append(new_param)
        else:
          param['value'] = new_param['value']

      def _create_param(self, key, value):
        """Create a new parameter with given key value pair.

        Args:
          key: parameter key.
          value: parameter value.

        Returns:
          parameter.
        """
        new_param = {}
        new_param['key'] = key
        if isinstance(value, str):
          new_param['value'] = {'stringValue': value}
        elif isinstance(value, int):
          new_param['value'] = {'intValue': value}
        elif isinstance(value, float):
          new_param['value'] = {'doubleValue': value}
        elif isinstance(value, bool):
          new_param['value'] = {'booleanValue': value}
        elif isinstance(value, dict):
          if 'type@' in value:
            new_param['value'] = {'protoValue': value}
          else:
            new_param['value'] = {
                'protoValue': {
                    '@type': 'type.googleapis.com/google.protobuf.Value',
                    'value': value
                }
            }
        elif isinstance(value, list):
          if not value:
            raise RuntimeError('Cannot create a param with empty list')
          if any(not isinstance(val, type(value[0])) for val in value):
            print('Not all elements in the list have the same type')
            new_param['value'] = {
                'protoValue': {
                    '@type': 'type.googleapis.com/google.protobuf.Value',
                    'value': value
                }
            }
          elif isinstance(value[0], str):
            new_param['value'] = {'stringArray': {'stringValues': value}}
          elif isinstance(value[0], int):
            new_param['value'] = {'intArray': {'intValues': value}}
          elif isinstance(value[0], float):
            new_param['value'] = {'doubleArray': {'doubleValues': value}}
          elif isinstance(value[0], bool):
            new_param['value'] = {'booleanArray': {'booleanValues': value}}
          elif isinstance(value[0], dict):
            if all('@type' in val and val['@type'] == value[0]['@type']
                   for val in value):
              new_param['value'] = {'protoArray': {'protoValues': value}}
            else:
              new_param['value'] = {
                  'protoValue': {
                      '@type': 'type.googleapis.com/google.protobuf.Value',
                      'value': value
                  }
              }
          else:
            raise RuntimeError('The type ' + type(value[0]) +
                               ' in the list is not supported')
        else:
          raise RuntimeError('Value ' + str(value) + ' has the type ' +
                             type(value) + ' that is not supported')
        return new_param

      def get(self, key):
        """Get the event parameter value for specified key.

        Args:
          key: parameter key.

        Returns:
          Parameter value.
        """
        param = self._get_param_by_key(key)
        if param is None:
          raise RuntimeError('Can not find param with key ' + key)
        return self._get_param_value(param)

      def _get_param_by_key(self, key):
        """Get the parameter for specified key.

        Args:
          key: parameter key.

        Returns:
          Parameter.
        """
        param = self._get_param_by_key_from_params(key, self._task_params)
        if param is None:
          return self._get_param_by_key_from_params(key, self._event_params)
        value = self._get_param_value(param)
        if isinstance(value, str) and len(value) > 2 and value.startswith(
            '$') and value.endswith('$'):
          return self._get_param_by_key_from_params(value[1:-1], self._event_params)
        return param

      def _get_param_by_key_from_params(self, key, params):
        """Get the parameter for specified key from event parameters.

        Args:
          key: parameter key.
          params: event parameters.

        Returns:
          Parameter.
        """
        if not isinstance(params, dict) or 'parameters' not in params:
          return None
        for param in params['parameters']:
          if param['key'] == key:
            return param
        return None

      def _get_param_value(self, param):
        """Get the parameter value for specified parameter.

        Args:
          param: parameter.

        Returns:
          Parameter value.
        """
        value = param['value']
        if len(value) != 1:
          raise RuntimeError('param does not have size of 1')
        for value_name in VALUE_NAME:
          if value_name in value:
            if value_name == 'protoValue' and value[value_name][
                '@type'] == VALUE_TYPE_URL:
              return value[value_name]['value']
            return value[value_name]
        for array_value_name in ARRAY_VALUE_NAME:
          if array_value_name in value:
            return value[array_value_name][ARRAY_VALUE_NAME[array_value_name]]
        raise RuntimeError('Cannot get value from param ' + str(param))

      def set_error(self):
        """Set the cloud function error to event parameters in order for user to see on IP."""

        self.set(CLOUD_FUNCTION_EXCEPTION_KEY, traceback.format_exc())

      def log(self, message):
        self._log.append(str(message))

      def get_response(self):
        """Get the response that can be returned to IP.

        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>`.
        """
        if self._log:
          self.set(CLOUD_FUNCTION_LOGGING_KEY, self._log)
        res = {
            'eventParameters': self._event_params,
        }
        return jsonify(res)


    def execute_function(request):
      """Entry point of the cloud function.

      Args:
        request (flask.Request): HTTP request object.

      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>`.
      """
      try:
        request_json = request.get_json(silent=True)
        event = _Event(request_json)
        run(event)
      except:
        event.set_error()
      return event.get_response()

    

requirements.txt

    # Function dependencies, for example:
    # package>=version
    

Para obtener más información sobre el formato de respuesta, consulta ValueType.

Java

En el siguiente ejemplo, se muestra cómo usar la tarea de Cloud Function en tu integración. Asegúrate de que la respuesta siga el formato JSON admitido como se describe en el ejemplo:

private static final Gson gson = new Gson();

@Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
  JsonObject body = gson.fromJson(request.getReader(), JsonObject.class);

  JsonArray resParams = new JsonArray();
  for (JsonElement param: body.getAsJsonObject("eventParameters").getAsJsonArray("parameters")) {
    if (param.getAsJsonObject().get("key").getAsString().equals("input")) {
      JsonObject newParam= new JsonObject();
      newParam.addProperty("key", "input");
      JsonObject value = new JsonObject();
      value.addProperty("stringValue","2");
      newParam.add("value", value);
      resParams.add(newParam);
    } else {
      resParams.add(param);
    }
  }
  JsonObject parameters = new JsonObject();
  parameters.add("parameters", resParams);
  JsonObject res = new JsonObject();
  res.add("eventParameters", parameters);
  System.out.println(res);
  BufferedWriter writer = response.getWriter();
  writer.write(res.toString());
}

Para obtener más información sobre el formato de respuesta, consulta ValueType.

JavaScript

En el siguiente ejemplo, se muestra cómo usar la tarea de Cloud Function en tu integración. Asegúrate de que la respuesta siga el formato JSON admitido como se describe en el ejemplo:

const functions = require('@google-cloud/functions-framework');

functions.http('execute_function', (req, res) => {
  console.log(JSON.stringify(req.body));
  let response = {"eventParameters":{"parameters":[{"key":"input","value":{"stringValue":"2"}}]}};
  res.send(JSON.stringify(response));
});

Para obtener más información sobre el formato de respuesta, consulta ValueType.

PHP

En el siguiente ejemplo, se muestra cómo usar la tarea de Cloud Function en tu integración. Asegúrate de que la respuesta siga el formato JSON admitido como se describe en el ejemplo:

use Psr\Http\Message\ServerRequestInterface;
function execute_function(ServerRequestInterface $request)
{
  return '{"eventParameters":{"parameters":[{"key":"input","value":{"stringValue":"2"}}]}}';
}

Para obtener más información sobre el formato de respuesta, consulta ValueType.

Edita una tarea de Cloud Function

Application Integration te dirige a la página de la consola Google Cloud adecuada para editar las funciones de Cloud Run según el tipo de versión.

Cloud Functions (1ª gen.)

Para editar una tarea de Cloud Function configurada con la versión de Cloud Functions (1ª gen.), realiza los siguientes pasos:

  1. En el panel de configuración de la tarea, haz clic en Abrir Cloud Function.

    Se te dirigirá a la página Cloud Functions (1ª gen.) > Detalles de la función en tu Google Cloud console.

  2. Haz clic en Editar.
  3. En la página Editar función, el paso Configuración te permite editar la configuración predeterminada de la Cloud Function. Consulta Configura Cloud Functions para obtener más información.
  4. Haz clic en Siguiente para continuar con el paso Código y editar el código fuente de Cloud Function.

    Según la configuración predeterminada, la Cloud Function contiene los siguientes archivos fuente:

    • main.py : Este archivo contiene el código de inicialización para ejecutar la Cloud Function desde tu integración.
    • task.py : este archivo contiene el código ejecutable de Cloud Function. Escribe tu secuencia de comandos dentro de la función run(event). Esta función se llama cuando se ejecuta la tarea de la función de Cloud Functions. El objeto event del archivo main.py contiene todos los parámetros de la tarea.

      Consulta Variables de integración de acceso para obtener información sobre cómo usar las variables definidas a nivel de integración en tu secuencia de comandos.

  5. Haz clic en Implementar.

Cloud Run Functions

Para editar una tarea de Cloud Function configurada con la versión de Cloud Functions (última gen.), realiza los siguientes pasos:

  1. En el panel de configuración de la tarea, haz clic en Abrir Cloud Function.

    Se te redireccionará a la página Cloud Run Functions > Detalles del servicio en tu Google Cloud console.

  2. En la pestaña Fuente, haz clic en Editar fuente para editar los archivos de código fuente de las funciones de Cloud Run.

    Según la configuración predeterminada, las funciones de Cloud Run contienen los siguientes archivos fuente:

    • main.py : Este archivo contiene el código de inicialización para ejecutar Cloud Functions desde tu integración.
    • task.py: este archivo contiene el código ejecutable de Cloud Functions. Escribe tu secuencia de comandos dentro de la función run(event). Se llama a esta función cuando se ejecuta la tarea de las funciones de Cloud Run. El objeto event del archivo main.py contiene todos los parámetros de la tarea.

      Consulta Variables de integración de acceso para obtener información sobre cómo usar las variables definidas a nivel de integración en tu secuencia de comandos.

  3. Haz clic en Guardar y volver a implementar.

Accede a variables de integración

Para acceder a una variable de integración en tu función de Cloud Functions, pasa la variable como parámetro de tarea a la tarea de Cloud Function. El parámetro de la tarea es un par clave-valor en el que Key es el nombre de la variable de referencia que se usa en su archivo fuente de Cloud Function y Value es el nombre de la variable de integración correspondiente a la que apunta la variable de la referencia. Puedes agregar uno o más parámetros de tarea en la sección Parámetros de tarea del panel de configuración de tareas.

Los siguientes métodos se usan para acceder a las variables de integración desde tu Cloud Function:

  • set: Establece el valor para una variable.
  • get: Lee el valor de una variable.

Por ejemplo, si tienes una variable de integración llamada EmployeeName que deseas usar en tu archivo de origen de Cloud Functions, define los siguientes parámetros de tareas:

  • Key: EmployeeKey
  • Value: EmployeeName

En la siguiente secuencia de comandos de ejemplo, se muestra el uso de las funciones set y get para acceder a las variables de integración definidas.

def run(event):  
  # Read the integration variable EmployeeName using the reference variable EmployeeKey
  value = event.get('EmployeeKey');
  # Change the integration variable EmployeeName value using the reference variable EmployeeKey
  event.set('EmployeeKey' , 'XYZ');
  # The new value of the integration variable is retained throughout the Cloud Function task.
  return

Estrategia de manejo de errores

Una estrategia de manejo de errores de una tarea específica la acción que se debe realizar si la tarea falla debido a un error temporal. Para obtener información sobre cómo usar una estrategia de manejo de errores y conocer los diferentes tipos de estrategias de manejo de errores, consulta Estrategias de manejo de errores.

Exclusiones del ANS

La tarea de Cloud Function tiene una dependencia de el producto Google Cloud Functions. Debido a que esta dependencia es externa a Application Integration, todas las ejecuciones de active integraciones que fallan debido a la falla en la tarea de Cloud Function se excluyen de los términos y condiciones del Acuerdo de Nivel de Servicio (ANS) de Application Integration.

Cuotas y límites

La tarea de Cloud Function tiene un límite de tiempo de espera de ejecución de 2 minutos (120 segundos). Si la función invocada tarda más de 2 minutos en completarse y responder, la tarea falla con un error de tiempo de espera de ejecución (TIMEOUT_WEB).

Si tu carga de trabajo requiere tiempos de ejecución superiores a 2 minutos, considera las siguientes soluciones alternativas:

  • Activador asíncrono con Pub/Sub: Usa una tarea o un conector de Pub/Sub en tu integración para publicar un mensaje de evento y configurar tus funciones de Cloud Run para que se activen de forma asíncrona desde la suscripción al tema de Pub/Sub para procesar la carga de trabajo en segundo plano.
  • Confirmación HTTP inmediata y devolución de llamada asíncrona: Configura tus funciones de Cloud Run activadas por HTTP para que muestren una respuesta HTTP 200 OK inmediata cuando reciban la solicitud, procesen la tarea de larga duración de forma asíncrona en segundo plano y, de manera opcional, invoquen un extremo de activador de la API de Application Integration para reanudar los pasos de integración descendentes una vez que se complete el procesamiento.

Para obtener información sobre las cuotas y los límites generales de las funciones de Cloud Run y Cloud Functions (1ª gen.), consulta Comparación de configuración.

¿Qué sigue?