Scheduled Lambda Execution

In this post we’ll setup a simple system for saving EC2 instance hours by stopping EC2 instances in the evening and starting them again in the morning, but the concepts can be applied to other recurring tasks such as database backups, taking snapshots of EBS volumes etc.

The ingredients we’ll mix in the solution are:

The Function

Let’s start with the AWS Lambda function which we’ll name “CloudNanny”. The function toggles EC2 instances between a running and stopped state. AWS Lambda currently supports functions written in Node.js, Java and Python. In this demo we’ll use Python together with the included AWS SDK for Python (Boto 3).

If the function is triggered by the custom WakeUp event it tries to start currently stopped instances. If the event is a custom BedTime event it instead tries to stop instances. The function only interacts with instances having the custom tag stopAtNight set.

import boto3

def toggle_instance(instance, start):
    ec2 = boto3.resource("ec2", region_name="eu-west-1")
    instance = ec2.Instance(instance["InstanceId"])
    if start:
def toggle_instances(start):
    ec2_client = boto3.client("ec2", region_name="eu-west-1")
    action_name = 'start' if start else 'stop'
    print('Looking for instances to {}'.format(action_name))
    # Look for the tag stopAtNight
    description = ec2_client.describe_instances( Filters=[ { 'Name': 'instance-state-name', 
        'Values': ['stopped' if start else 'running'] },
        { 'Name': 'tag-key', 'Values' : ['stopAtNight'] }])
    for reservation in description["Reservations"]:
        for instance in reservation["Instances"]:
            print('instance to {}: {}'.format(action_name, instance["InstanceId"]))
            toggle_instance(instance, start)

def lambda_handler(event, context):
    toggle_instances("WakeUp" in event["resources"][0])

Execution Scheduling

The mechanism used to trigger the AWS Lambda function in this example is the recently introduced CloudWatch Events. CloudWatch Events can be delivered to a target. In our example we want the WakeUp and BedTime event to be delivered to a the CloudNanny function target.

As we want our event to be emitted on a fixed rate we’ll supply a Cron expression to the aws events put-rule command:

aws events put-rule --name Nanny-BedTime --schedule-expression 'cron(55 21 * * ? *)' --description "Bedtime signal"
aws events put-rule --name Nanny-WakeUp --schedule-expression 'cron(0 6 * * ? *)' --description "Wakeup signal"

This means that the Nanny-BedTime event will be generated daily at 21:55 and the Nanny-WakeUp event will be generated at 06:00.

The aws events put-targets command is then used to target the function, i.e. linking the event with the function.

aws events put-targets --rule Nanny-BedTime --targets '{"Id":"1", "Arn":"arn:aws:lambda:eu-west-1::function:CloudNanny"}'

When the event fires CloudWatch will invoke the lambda and pass the event as an argument to the function.

Demo Setup

Download the code from the github repository then run the script to set up the CloudNannyExection role which will grant access to EC2 and to CloudWatch Logs (for logging execution results).

  "Version": "2012-10-17",
  "Statement": [
      "Effect": "Allow",
      "Action": [
      "Resource": "*"
      "Effect": "Allow",
      "Action": [
      "Resource": "arn:aws:logs:*:*:*"

The CloudNannyExection role also gets a trust policy which allows AWS lambda functions to assume the role.

  "Version": "2012-10-17",
  "Statement": [
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": ""
      "Action": "sts:AssumeRole"

With the CloudNannyExection role in place the function can now be deployed using the script which uploads the function and wires it with the WakeUp and BedTime rules.


If you make modification to the function just rerun the deploy script to upload an updated version. To change scheduling modify and run the or the script.


With CloudWatch Events it’s now possible to fully script deployment of cron scheduled invocations of AWS lambda functions. The demo presented here can be easily be modified to handle other tasks.

One thing to watch out for however is that lambda function are supposed to be quick so for long-running jobs you might be better off running normal cron jobs on a small and cheap t2.nano instance; but when possible try to use AWS lambda functions and you don’t need to worry about setting up and monitoring servers yourself.

Leave a Reply