Una función que espera noticias
Un handler de Lambda es una función. Un servicio de la nube la llama por ti cuando ocurre algo, como que llegue una foto a un bucket de S3. La noticia llega como un diccionario llamado evento.
En este módulo escribes el handler y lo pruebas en tu propio ordenador. No se despliega nada en ninguna parte, y los eventos se inventan a mano.
Al final de esta lección
Nota
Puedo escribir un handler que lee un evento y devuelve un resultado.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Handler | la función a la que llama el servicio | handler(event, context) |
| Evento | un diccionario que describe lo que ocurrió | |
| Registro | una noticia de la lista del evento | Record |
| Fixture | un evento inventado que se guarda para probar | |
| Idempotente | seguro de ejecutar dos veces con el mismo resultado |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Un handler recibe un evento y un contexto
Un handler es una función normal de Python con dos parámetros. event lleva la noticia. context lleva datos de la función en marcha, como cuánto tiempo puede durar.
La función devuelve un resultado. Como es solo una función, puedes llamarla tú mismo con un evento inventado.
No está desplegado en ninguna parte
Nota
En este módulo no se sube ninguna función. Las formas de evento de aquí son las documentadas que recibe una función, no la salida de una pila tuya. Pruebas llamando a la función a mano.
Run: llama a un handler a mano
event = {
"Records": [
{
"eventSource": "aws:s3",
"eventName": "ObjectCreated:Put",
"s3": {"bucket": {"name": "tienda-subidas"}, "object": {"key": "imagenes/gato.png", "size": 1024}},
}
]
}
def handler(event, context):
first = event["Records"][0]
bucket = first["s3"]["bucket"]["name"]
key = first["s3"]["object"]["key"]
return {"stored": bucket + "/" + key}
print(handler(event, None))
# Cambia la clave a imagenes/perro.png y vuelve a ejecutarlo.
Un evento lleva una lista de registros
Un evento puede llevar varios registros, así que un handler recorre Records. Cada registro dice de dónde viene en eventSource.
Un registro de S3 nombra un bucket y una clave. Un registro de SQS, de una cola, tiene un body. El cuerpo es un texto, así que un cuerpo JSON necesita json.loads antes de poder leerlo.
Ejemplo resuelto: dos clases de registro
| Campo | Registro de S3 | Registro de SQS |
|---|---|---|
| eventSource | aws:s3 | aws:sqs |
| Qué ocurrió | eventName, como ObjectCreated:Put | un mensaje en body |
| Dónde mirar | s3.bucket.name y s3.object.key | body, un texto JSON |
| Un id único | ninguno fiable | messageId |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Run: lee las dos clases de registro
import json
event = {"Records": [
{"eventSource": "aws:sqs", "messageId": "m-1", "body": "{\"order\": 1, \"item\": \"te\"}"},
{"eventSource": "aws:s3", "eventName": "ObjectCreated:Put",
"s3": {"bucket": {"name": "tienda-subidas"}, "object": {"key": "registros/web.log"}}},
]}
def handler(event, context):
seen = []
for record in event["Records"]:
if record["eventSource"] == "aws:sqs":
order = json.loads(record["body"])
seen.append("pedido " + str(order["order"]))
elif record["eventSource"] == "aws:s3":
seen.append("archivo " + record["s3"]["object"]["key"])
return seen
print(handler(event, None))
Un handler puede ver una noticia dos veces
Una cola promete entrega al menos una vez. El mismo mensaje puede llegar dos veces a tu función, por ejemplo tras una ejecución lenta.
Un handler es idempotente cuando una segunda ejecución no cambia nada. Apunta lo que terminaste y salta el trabajo ya apuntado. Una función real guarda esa nota en una tabla, y la lección de la cadena de servicios usa una. Aquí la sustituye un conjunto.
Un error frecuente
Advertencia
Mucha gente cree que cada mensaje llega una sola vez. No es así: la entrega es al menos una vez. Haz el handler seguro de ejecutar dos veces, o un pedido se cobra dos veces.
Run: salta lo que ya se hizo
def handle(orders, done):
newly = []
for order in orders:
if order in done:
continue
done.add(order)
newly.append(order)
return newly
done = set()
print(handle([1, 2, 2], done))
print(handle([2, 3], done))
# Añade el pedido 4 a la segunda lista. ¿Qué muestra ahora la segunda línea?