Cuando trabajamos con serverless Ver figura 1 (que su traducción literal no le haría mucha justicia) nos encontraremos con algunos problemas, esto debido a  que  cambia el paradigma del que venimos desarrollando, aquí se crea una capa de abstracción a nivel de código, lo que implica al desarrollador no tener que pensar en algunas responsabilidades como por el ejemplo: el enrutamiento, lo efímero de las funciones (su tiempo de vida es durante su ejecución), no se tiene escritura y lectura (podría usar algún servicio bucket), y es código que persigue el principio de SOLID donde se habla de la responsabilidad única, todo este paradigma conlleva algunos errores que se cometen cuando se ingresa a trabajar con functions as a service, por ello en este artículo me enfocaré y resaltare algunos

Figura 1: los servidores sin trabajo? obtenido de https://dzone.com/articles/serverless-economic-impact-comic

Timeout

Como mencione anteriormente las lambda functions son efímeras, esto quiere decir que tienen un tiempo en el que inicia y finaliza su ejecución, este tiempo por defecto es de 6 segundos, si por alguna razón este tiempo se sobrepasa, te retornará un error 502 "matando la conexión", hacer el debug cuando esto sucede es bastante complejo, por eso el parámetro timeout les evitará este problema, que generalmente sucede cuando se tiene algún servicio que se llama desde la lambda y  que es algo lento, la configuración del serverless.yaml se aprecia a continuación


service: mylambdaproject

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: us-east-1


functions:
  search:
    handler: src.service.search.search
    timeout: 10
    events:
      - http:
          path: search
          method: post
          cors: true

Variables de entorno

Seguramente al trabajar con repositorios de código, se necesitará tener las claves y los key ocultos, para ello en las lambdas también se pueden usar variables de entorno, en serverless específicamente se tienen varios tipos de variable, opt, self y de archivo, ami personalmente me pareció más ordenado utilizar variables de entorno con archivos, para el ejemplo se vería de la siguiente forma el serverless.yaml


service: mylambdaproject

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: us-east-1
  environment:
    API: ${file(./config.${opt:stage, 'dev'}.json):API}

functions:
  search:
    handler: src.service.search.search
    timeout: 10
    events:
      - http:
          path: search
          method: post
          cors: true
{

  "API": "https://jairoandres.com"
}
Archivo donde se guarda la variable

en este ejemplo las variables se cargan a todas las funciones, pero podrían cargarse solo por funciones individuales

AWS profiler

Cuando se van a hacer deploy en diferentes proyectos, se pueden tener diferentes cuentas de AWS para ello se puede utilizar aws-profiler que permite crear y usar diferentes credenciales

serverless config credentials --provider aws --key 1234 --secret 5678 --profile personal-count

en el archivo ~/.aws/credentials tendríamos algo similar a esto

[personal-count]
aws_access_key_id=***************
aws_secret_access_key=***************

y así cuando se realice el deploy se agrega el profiler

sls deploy --aws-profile personal-count

ahora, aquí puede darse un dolor de cabeza ya que puede generar el siguiente error

The security token included in the request is expired

para corregirlo se utiliza el siguiente comando

aws configure set aws_session_token your_token

esto sucede ya que al tener varias cuentas de AWS, el token de la cuenta personal, o por defecto puede estar usando el token erróneo, por ende debe setearse

Utilizar un mismo bucket

Cuando se despliega una lambda, el código del proyecto es subido o guardado en un bucket, por defecto serverless te crea el bucket para cada  proyecto y guarda el código de las funciones, sin embargo se es muy común el caso de que en los despliegues se deseen guardar todas las lambdas en un mismo bucket, para ello se puede utilizar el siguiente plugin que garantiza el proceso de manera exitosa

 serverless plugin install --name serverless-deployment-bucket

y se agrega la siguiente configuración al archivo serverless.yaml


service: mylambdaproject

frameworkVersion: '2'

provider:
  deploymentBucket:
    name: ejemplo-test
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: us-east-1
  environment:
    API: ${file(./config.${opt:stage, 'dev'}.json):API}

functions:
  search:
    handler: src.service.search.search
    timeout: 10
    events:
      - http:
          path: search
          method: post
          cors: true


plugins:
  - serverless-deployment-bucket

el deployment bucket queda de manera global en el provider, este es llamado ejemplo-test, si este no llegara a existir serverless lo creara como el procedimiento normal

Requirements y el espacio

El cambio de paradigma implica que todo lo que necesite la función debe subirse en el código, es decir no se tienen los entornos virtuales que generalmente se usan, eso no implica que no se puedan instalar dependencias, para ello con el siguiente plugin lo que hace serverless es subir el código de las dependencias por nosotros y nos ahorra un poco de trabajo

 serverless plugin install --name serverless-python-requirement

y ahora adicionalmente si usamos un entorno virtual o cualquier carpeta que no se requiera subir en desarrollo, podemos agregar la siguiente configuración


service: mylambdaproject

frameworkVersion: '2'

provider:
  deploymentBucket:
    name: ejemplo-test
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: us-east-1
  environment:
    API: ${file(./config.${opt:stage, 'dev'}.json):API}

functions:
  search:
    handler: src.service.search.search
    timeout: 10
    events:
      - http:
          path: search
          method: post
          cors: true


package:
  exclude:
    - node_modules/**
    - venv/**


plugins:
  - serverless-deployment-bucket
  - serverless-python-requirements

con esta configuración en el serverless.yaml, cada vez que se despliegue buscará el archivo requirements.txt , se instalarán las dependencias locales y se subirán con el código del lambda, pero además la carpeta de entorno virtual, en mi caso llamada .venv no se subirá, esto debido a que el exclude evita que se suban carpetas o documentos que no se desean tener guardadas con la función, recordando que el espacio es un atributo fundamental, pues es bastante limitado en las funciones

Conclusión

Existen muchos errores que pueden resultar al trabajar con lambdas, sobre todo al comienzo debido al cambio de paradigma, he descrito algunos que seguramente ayudarán a ahorrar un poco de tiempo buscando la solución, pero sin duda me han sucedido algunos otros que espero continuar en un siguiente artículo