Part 5: Add S3 delete event handler

Now that we are automatically importing uploaded images to our table, we need to be able to automatically delete images from our table that get deleted from our bucket. This can be accomplished by doing the following:

Add Lambda function for S3 object deletion

Add a new Lambda function that is invoked whenever an object is deleted from the S3 bucket and if it is an image, removes the image from the table.

Instructions

  1. In the app.py file add a new function handle_object_removed that is triggered whenever an object gets deleted from the bucket and deletes the item from table if it is an image:

@app.on_s3_event(bucket=os.environ['MEDIA_BUCKET_NAME'],
                 events=['s3:ObjectRemoved:*'])
def handle_object_removed(event):
    if _is_image(event.key):
        get_media_db().delete_media_file(event.key)

Verification

  1. Ensure the contents of the app.py file is:

 1import os
 2
 3import boto3
 4from chalice import Chalice
 5from chalicelib import db
 6from chalicelib import rekognition
 7
 8app = Chalice(app_name='media-query')
 9
10_MEDIA_DB = None
11_REKOGNITION_CLIENT = None
12_SUPPORTED_IMAGE_EXTENSIONS = (
13    '.jpg',
14    '.png',
15)
16
17
18def get_media_db():
19    global _MEDIA_DB
20    if _MEDIA_DB is None:
21        _MEDIA_DB = db.DynamoMediaDB(
22            boto3.resource('dynamodb').Table(
23                os.environ['MEDIA_TABLE_NAME']))
24    return _MEDIA_DB
25
26
27def get_rekognition_client():
28    global _REKOGNITION_CLIENT
29    if _REKOGNITION_CLIENT is None:
30        _REKOGNITION_CLIENT = rekognition.RekognitonClient(
31            boto3.client('rekognition'))
32    return _REKOGNITION_CLIENT
33
34
35@app.on_s3_event(bucket=os.environ['MEDIA_BUCKET_NAME'],
36                 events=['s3:ObjectCreated:*'])
37def handle_object_created(event):
38    if _is_image(event.key):
39        _handle_created_image(bucket=event.bucket, key=event.key)
40
41
42@app.on_s3_event(bucket=os.environ['MEDIA_BUCKET_NAME'],
43                 events=['s3:ObjectRemoved:*'])
44def handle_object_removed(event):
45    if _is_image(event.key):
46        get_media_db().delete_media_file(event.key)
47
48
49def _is_image(key):
50    return key.endswith(_SUPPORTED_IMAGE_EXTENSIONS)
51
52
53def _handle_created_image(bucket, key):
54    labels = get_rekognition_client().get_image_labels(bucket=bucket, key=key)
55    get_media_db().add_media_file(key, media_type=db.IMAGE_TYPE, labels=labels)

Redeploy the Chalice application

Deploy the updated Chalice application with the new Lambda function.

Instructions

  1. Run chalice deploy:

    $ chalice deploy
    Creating IAM role: media-query-dev-handle_object_removed
    Creating lambda function: media-query-dev-handle_object_removed
    Configuring S3 events in bucket media-query-mediabucket-fb8oddjbslv1 to function media-query-dev-handle_object_removed
    Resources deployed:
      - Lambda ARN: arn:aws:lambda:us-west-2:123456789123:function:media-query-dev-handle_object_created
      - Lambda ARN: arn:aws:lambda:us-west-2:123456789123:function:media-query-dev-handle_object_removed
    

Verification

  1. Delete the uploaded othersample.jpg object from the previous part:

    $ aws s3 rm s3://$MEDIA_BUCKET_NAME/othersample.jpg
    
  2. Use the scan CLI command to ensure the object is no longer in the table:

    $ aws dynamodb scan --table-name $MEDIA_TABLE_NAME
    {
        "Items": [
            {
                "name": {
                    "S": "sample.jpg"
                },
                "labels": {
                    "L": [
                        {
                            "S": "Animal"
                        },
                        {
                            "S": "Canine"
                        },
                        {
                            "S": "Dog"
                        },
                        {
                            "S": "German Shepherd"
                        },
                        {
                            "S": "Mammal"
                        },
                        {
                            "S": "Pet"
                        },
                        {
                            "S": "Collie"
                        }
                    ]
                },
                "type": {
                    "S": "image"
                }
            }
        ],
        "Count": 1,
        "ScannedCount": 1,
        "ConsumedCapacity": null
    }
    

    If the item still appears, try running the scan command after waiting for ten seconds. Sometimes, it takes a little bit of time for the Lambda function to get triggered. In the end, the table should only have the sample.jpg item.