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

Free lesson

Queues: send, receive and delete

After this lesson: I can say what happens to a message from send to delete.

55 min lesson6 commandsCloud lab: practise S3 buckets, SQS queues and DynamoDB tables with the AWS command line

A queue of orders, like a café queue

A message queue, such as Amazon SQS, holds messages in line until a program is ready to handle them. It lets a busy shop take orders faster than its workers can process them, and lose none.

Think of a café queue. A customer joins at the back, and the server takes the person at the front. A shop drops each new order into an SQS queue, and a worker takes them one at a time.

By the end of this lesson

Note

I can say what happens to a message from send to delete.

Key words

WordWhat it means
Queuea line of messages waiting to be handled
Messageone piece of text waiting in a queue
Receiveto ask the queue for messages to work on
Visibility timeouthow long a received message stays hidden
Receipt handlethe ticket that lets you delete a received message
At-least-oncea message may arrive more than once, but it always arrives at least once

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

A receive hands you a message

send_message puts text on the queue. Its answer holds a MessageId. receive_message asks for messages. Its answer holds a list called Messages.

Each message has a Body, which is the text, and a ReceiptHandle. A body is only text. Many shops store JSON in it, and the worker turns it back into a dictionary with json.loads.

Worked example: a receive answer

FieldWhat it holdsExample
Messagesa list with one dictionary per messagetwo messages
MessageIdthe id the queue gave at sendm-1
Bodythe text that was sent{"order": 1, "item": "tea"}
ReceiptHandlethe ticket for deleting this receiveh-1
ApproximateReceiveCounthow many times it was received, as text"1"

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

Run it: read a receive answer

Code: python
import json
answer = {
    "Messages": [
        {"MessageId": "m-1", "ReceiptHandle": "h-1",
         "Body": "{\"order\": 1, \"item\": \"tea\"}",
         "Attributes": {"ApproximateReceiveCount": "1"}},
        {"MessageId": "m-2", "ReceiptHandle": "h-2", "Body": "two",
         "Attributes": {"ApproximateReceiveCount": "1"}},
    ]
}
for message in answer["Messages"]:
    print(message["MessageId"], message["Body"])
order = json.loads(answer["Messages"][0]["Body"])
print("item:", order["item"])
# Change the loop to print the ReceiptHandle as well.

A received message is hidden, not gone

Receive does not remove a message. It hides it for the visibility timeout, which is 30 seconds on the captured queue. Other workers cannot receive it while it is hidden.

When the work is done, call delete_message with the ReceiptHandle. Only then is the message gone. If the worker crashes first, the timeout ends and the message becomes visible again for another worker.

Worked example: a queue's attributes

AttributeValueMeaning
VisibilityTimeout"30"seconds a received message stays hidden
ApproximateNumberOfMessages"3"messages waiting to be received
ApproximateNumberOfMessagesNotVisible"0"messages hidden after a receive
MessageRetentionPeriod"345600"seconds a message is kept, which is four days

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

Run it: hidden, then visible again

Code: python
TIMEOUT = 30
received_at = {"m-1": 100}


def is_visible(message_id, now):
    if message_id not in received_at:
        return True
    return now >= received_at[message_id] + TIMEOUT


for now in [100, 120, 130, 160]:
    print(now, is_visible("m-1", now))
print("m-2 never received:", is_visible("m-2", 100))
# Change TIMEOUT to 60. At which times is m-1 visible now?

A common mistake

Warning

Many people think a receive removes the message. It only hides it. If you never call delete_message, the message comes back after the timeout and is handled again. Delete it once the work is done, never before.

At-least-once means repeats happen

The queue keeps a message until it is deleted, so a message can arrive twice. A worker may finish the work and crash before the delete.

A receive may also return fewer messages than you asked for, or none. An empty answer has no Messages key, so check for the key before you read it. Write the worker so that a repeat does no harm.

Run it: skip a repeat

Code: python
deliveries = ["m-1", "m-2", "m-1", "m-3"]
done = []
for message_id in deliveries:
    if message_id in done:
        print(message_id, "again: skip it")
    else:
        done.append(message_id)
        print(message_id, "first time: do the work")

empty = {}
if "Messages" in empty:
    print("messages:", len(empty["Messages"]))
else:
    print("messages: 0")
# Add print(empty["Messages"]) at the end. What goes wrong?

Try it in the cloud lab

The cloud lab is a practice copy of S3, SQS and DynamoDB. Press Start the lab on the bar, then press Run on each command below. They use the real AWS command line, so the same words work on a real account. After the delete, press Run on the receive again: it prints nothing, because the queue is empty. This step is for practice. The assignment below stays plain Python, so you can do it without the lab.

Set a made-up key and the lab's address

Command
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://cloud:4566

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Make a queue

Command
Q=$(aws sqs create-queue --queue-name orders --query QueueUrl --output text)

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Send a message

Command
aws sqs send-message --queue-url $Q --message-body "order 1"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Receive it and save the reply

Command
aws sqs receive-message --queue-url $Q | tee reply.json

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Keep its receipt handle

Command
H=$(grep -o '"ReceiptHandle": "[^"]*"' reply.json | cut -d'"' -f4)

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Delete the message

Command
aws sqs delete-message --queue-url $Q --receipt-handle "$H"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

About this lab and its source: Cloud lab: practise S3 buckets, SQS queues and DynamoDB tables with the AWS command line

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