En abril de 2021 AWS lanzó la posibilidad para que desde una instancia de RDS PostgreSQL se pueden hacer invocaciones a funciones Lambda. Una función Lambda nos permite ejecutar código sin tener que aprovisionar o manejar servicios y sin preocuparnos por la escalabilidad. Anteriormente escribí como crear una función lambda con Java y pueden encontrar el artículo aquí.

Gracias a este nuevo lanzamiento nos resulta posible invocar funciones Lambda directamente desde una base de datos de Amazon RDS para PostgreSQL; ya sea a través de procedimientos almacenados o funciones definidas por el usuario. Esto nos permite ampliar las capacidades de la base de datos e invocar aplicaciones externas para actuar sobre los cambios de datos.

Por ejemplo, podemos invocar una función Lambda que envié correos electrónicos por medios de SES cuando se registra un cambio en la base de datos; o quizás enviar un mensaje a una cola de SQS.

Las posibilidades son ilimitadas.

Este este artículo vamos a hacer un ejercicio al respecto, primeramente debemos saber que necesitamos estar usando al menos la versión 12.6 o la 13.2 en adelante de PostgreSQL; para nuestro ejemplo usaremos la versión 13.2-R1.

Prerrequisitos

Seguidamente abordaremos los prerrequisitos que debemos hacer para poder ejecutar nuestro Lambda desde PostgreSQL.

Extensión en PostgreSQL

El primer paso que debemos hacer es instalar una nueva extensión en nuestra base de datos.

CREATE EXTENSION IF NOT EXISTS aws_lambda CASCADE;

El resultado debe ser exitoso y además nos indica que se agrega una extensión adicional que es aws_commons.

Crear Extension

Función Lambda

El siguiente paso es tener una función Lambda ya disponible para usar, de ella debemos tomar nota del nombre (o su ARN, versión o alias). Como se aprecia en la siguiente imagen, en nuestro caso el ARN es: arn:aws:lambda:us-east-1:338068911589:function:DemoLambda

Lambda

Política de IAM

Ahora debemos dar permisos a RDS para que pueda invocar nuestra Lambda. Así que debemos crear una política de IAM que da permisos de ejecución a nuestra función; observen que usamos el ARN del cual tomamos nota antes.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": "arn:aws:lambda:us-east-1:338068911589:function:DemoLambda"
        }
    ]
}

En mi caso a esta política le puse el nombre RDS-Lambda-Policy; como se ilustra de seguido.

Lambda

Debemos tomar nota del ARN de está política y que en mi ejemplo es: arn:aws:iam::338068911589:policy/RDS-Lambda-Policy.

Lambda

Rol de IAM

Continuamos creando un rol de IAM. Este rol será asumido por RDS para ejecutar la función Lambda y este sería creado desde el CLI de esta manera:

aws iam create-role  --role-name rds-lambda-role --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
        {
        "Effect": "Allow",
        "Principal": {
            "Service": "rds.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
        }
    ]
}'

Debemos asociar nuestra política a este rol; como vemos en la siguiente imagen:

Lambda

El resultado sería este:

Lambda

Asignar el Rol a RDS

El último paso de preparación es asignar este rol rds-lambda-role a nuestra instancia de RDS. Esto lo hacemos en Manage IAM Roles de nuestra instancia. Es importante que en feature se seleccione Lambda.

Lambda

Debemos esperar algunos minutos a que el role este asociado y activo.

Lambda

Demostración

Luego de todo lo anterior; llego el momento de poder ejecutar nuestra función desde PostgreSQL.

Esto se hace por medio de la función aws_lambda.invoke, como se ilustra de seguido:

SELECT * FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('DemoLambda', 'us-east-1'),
'{"name": "Gerardo",
  "greeting": "Hola"}'::json
);

y obtenemos nuestra respuesta exitosa!

Lambda

Observen que dado que la ejecución fue sincrónica, tenemos acceso a la respuesta que nos da el Lambda. Por tanto, podemos usar esa respuesta para implementar lógica adicional en un procedimiento almacenado o función.

Si revisamos en la consola de Lambda, veremos nuestras invocaciones reflejadas en las métricas.

Lambda

Ahora, desglosemos esta invocación.

SELECT * FROM aws_lambda.invoke(aws_commons.
  create_lambda_function_arn('DemoLambda', 'us-east-1'),
'{"name": "Gerardo",
  "greeting": "Hola"}'::json
);

Notaran que el aws_lambda.invoke tiene como primer parámetro una estructura aws_commons._lambda_function_arn_1. Para obtenerla debemos usar la función create_lambda_function_arn de la extensión aws_commons. Esta recibe dos parámetros: el nombre, ARN o versión de la función y la región donde esta alojada.

Entonces, podemos usar varias maneras para obtener una estructura aws_commons._lambda_function_arn_1; ya sea por nombre:

SELECT aws_commons.create_lambda_function_arn(
   'DemoLambda',
   'us-east-1'
)

o bien por ARN

SELECT aws_commons.create_lambda_function_arn(
   'arn:aws:lambda:us-east-1:338068911589:function:DemoLambda',
   'us-east-1'
)

¿Podría ejecutar el Lambda de manera asincrónica?

Y la respuesta es afirmativa y con un simple ajuste: agregar a la invocación un tercer parámetro ‘Event’

SELECT * FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn('DemoLambda', 'us-east-1'),
'{"name": "Gerardo",
  "greeting": "Hola"}'::json,
  'Event'
);
Lambda

Observen que no tenemos el resultado de la ejecución, así que podemos hacer uno de este tipo de llamada cuando no necesitamos conocer la respuesta del Lambda.

¿Y el Rollback?

Algo importante que deben considerar; imaginen que tienen un procedimiento almacenado que realiza un proceso determinado y uno de sus pasos es llamar a un Lambda. Supongamos que ya ejecutó ese paso y en los subsiguientes hay un error y por tanto se genera un rollback de la base de datos.

No olviden que a nivel de la BD el rollback fue exitoso y pero el Lambda si se ejecutó y RDS no es responsable por hacer un rollback de esa Lambda.

Es nuestra responsabilidad que invoquemos un proceso que reverse o compense de manera lógica lo que haya hecho esa función.

Por ejemplo: si el lambda enviaba un correo de confirmación, nuestra compensación quizás sea otro correo para indicar que se omita el previo.

Conclusión

Espero que este artículo les haya sido de utilidad y que se animen a realizar algunas pruebas con PostgreSQL y Lambdas; especialmente si forman parte de los proyectos en los cuales estén trabajando.