Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

A Lambda handler and its event

After this lesson: I can write a handler that reads an event and returns a result.

55 min lessonNo commands

A function that waits for news

A Lambda handler is a function a cloud service calls for you when something happens, such as a photo landing in an S3 bucket. The news arrives as a dictionary called an event.

In this module you write the handler and test it on your own computer. Nothing is deployed anywhere, and the events are made up by hand.

By the end of this lesson

Note

I can write a handler that reads an event and returns a result.

Key words

WordWhat it meansExample
Handlerthe function the service callshandler(event, context)
Eventa dictionary describing what happened
Recordone item in the event's list of news
Fixturea made-up event kept for testing
Idempotentsafe to run twice with the same result

The cells students fill in are left blank in this preview.

A handler takes an event and a context

A handler is an ordinary Python function with two parameters. event holds the news. context holds facts about the running function, such as how long it may run.

The function returns a result. Because it is only a function, you can call it yourself with a made-up event.

Not deployed anywhere

Note

No function is uploaded in this module. The event shapes here are the documented ones a function receives, not output from a stack of yours. You test by calling the function by hand.

Run: call a handler by hand

Code: python
event = {
    "Records": [
        {
            "eventSource": "aws:s3",
            "eventName": "ObjectCreated:Put",
            "s3": {"bucket": {"name": "shop-uploads"}, "object": {"key": "images/cat.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))
# Change the key to images/dog.png and run it again.

An event holds a list of records

One event can carry several records, so a handler loops over Records. Each record says where it came from in eventSource.

An S3 record names a bucket and a key. An SQS record, from a queue, has a body. The body is a string, so a JSON body needs json.loads before you can read it.

Worked example: two kinds of record

FieldS3 recordSQS record
eventSourceaws:s3aws:sqs
What happenedeventName, such as ObjectCreated:Puta message in body
Where to looks3.bucket.name and s3.object.keybody, a JSON string
A unique idnone to rely onmessageId

The cells students fill in are left blank in this preview.

Run: read both kinds of record

Code: python
import json

event = {"Records": [
    {"eventSource": "aws:sqs", "messageId": "m-1", "body": "{\"order\": 1, \"item\": \"tea\"}"},
    {"eventSource": "aws:s3", "eventName": "ObjectCreated:Put",
     "s3": {"bucket": {"name": "shop-uploads"}, "object": {"key": "logs/web.log"}}},
]}

def handler(event, context):
    seen = []
    for record in event["Records"]:
        if record["eventSource"] == "aws:sqs":
            order = json.loads(record["body"])
            seen.append("order " + str(order["order"]))
        elif record["eventSource"] == "aws:s3":
            seen.append("file " + record["s3"]["object"]["key"])
    return seen

print(handler(event, None))

A handler may see the same news twice

A queue promises at-least-once delivery. The same message can reach your function twice, for example after a slow run.

A handler is idempotent when a second run changes nothing. Keep a note of what you finished, and skip any work already noted. A real function keeps that note in a table, as the pipeline lesson does. Here a set stands in for it.

A common mistake

Warning

Many people think each message arrives once. It does not: delivery is at least once. Make the handler safe to run twice, or one order is charged twice.

Run: skip what was already done

Code: python
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))
# Change the second list to [4, 1]. Predict the second line before you Run.

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.