Run Crons with Lambda in AWS and EventBridge

AWS Lambda crons with EventBridge: package a Python script, schedule it to run every 6 hours serverlessly, automate deployment with a Makefile, then clean up.

Automation is at the heart of reliable cloud systems. Whether you want to fetch weather data, clean logs, update caches, or ping a health endpoint, scheduled tasks (aka cron jobs) are essential.

Traditionally, cron jobs lived on servers. But in the cloud-native world, we aim to make our tasks serverless, secure, and scalable. Enter:

  • AWS Lambda — for running lightweight, event-driven functions.
  • Amazon EventBridge (formerly CloudWatch Events) — for triggering those functions on a schedule (like crontab).

In this guide, we’ll explore how to:

  • Package a Python script for AWS Lambda
  • Run it every 6 hours using EventBridge
  • Automate deployment with a Makefile
  • Clean up all resources when you’re done

Let’s dive in.

The Code Logic

Let’s say we have a Python script that:

  • Fetches weather data from WeatherAPI
  • Sends that data to a debug API endpoint for processing or logging

Here’s our logic saved in src/script.py:

import json
import os

import requests

def get_weather_data(city="Nairobi"):
    api_key = os.environ.get("WEATHERAPI_KEY", "e35b01c9046641c2af095849252503")
    url = f"http://api.weatherapi.com/v1/current.json?key={api_key}&q={city}"

    try:
        response = requests.get(url)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error fetching weather data: {e}")
        return None

def send_to_jsonplaceholder(data):
    url = "https://stage-opsman-api.citizix.com/debug-request"
    payload = {
        "title": f"Weather Report for {data['location']['name']}",
        "body": f"Temperature: {data['current']['temp_c']}°C, Conditions: {data['current']['condition']['text']}, Humidity: {data['current']['humidity']}%",
        "userId": 1
    }

    try:
        response = requests.post(url, json=payload)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error sending data: {e}")
        return None

def main():
    city = os.environ.get("WEATHER_CITY", "Nairobi")
    weather_data = get_weather_data(city)

    if weather_data:
        print(f"Successfully retrieved weather data for {city}")
        result = send_to_jsonplaceholder(weather_data)

        if result:
            print(f"Successfully sent data to JSONPlaceholder API")
            print(f"Response: {json.dumps(result, indent=2)}")
        else:
            print("Failed to send data to JSONPlaceholder API")
    else:
        print(f"Failed to retrieve weather data for {city}")


if __name__ == "__main__":
    main()

Lambda Entry Point

We wrap this in a Lambda-compatible handler in src/main.py:

from script import main


def handler(event, context):
    main()
    return {'statusCode': 200}

This is the file AWS Lambda will call when the function is triggered.

Packaging the Code

To make Lambda understand your code:

  • Add dependencies in requirements.txt:
requests
  • Install them locally into src/:
pip install -r requirements.txt -t ./src
  • Package the folder:
cd src && zip -r ../make-health-check.zip .

This ZIP will be uploaded to AWS as your Lambda function code.

Creating IAM Role for Lambda

AWS Lambda needs permissions to run. So, we create a role and attach basic execution permissions:

  • Trust policy
cat > trust-policy.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

Create Iam role

aws iam create-role --role-name MakeHealthCheckRole --assume-role-policy-document file://trust-policy.json

Attach basic execution policy

aws iam attach-role-policy --role-name MakeHealthCheckRole --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

Get role arn

aws iam get-role --role-name MakeHealthCheckRole --query 'Role.Arn' --output text

Deploying the Lambda Function

Use the zipped code to create the Lambda function:

zip -r make-monitor.zip .

aws lambda create-function \
  --function-name MakeHealthCheck \
  --zip-file fileb://make-monitor.zip \
  --handler main.handler \
  --runtime python3.12 \
  --role arn:aws:iam::<your-account-id>:role/MakeHealthCheckRole \
  --timeout 30

Make sure to replace <your-account-id> with your real AWS account number.

Setting Up a Cron with EventBridge

AWS EventBridge allows us to run the Lambda every 6 hours using a cron expression:

aws events put-rule \
  --name MakeHealthCheckSchedule \
  --schedule-expression "cron(0 0/6 * * ? *)"

This runs the function at 00:00, 06:00, 12:00, and 18:00 UTC daily.

Give EventBridge Permission to Trigger Lambda

Add permission for CloudWatch to invoke Lambda

aws lambda add-permission \
  --function-name MakeHealthCheck \
  --statement-id MakeHealthCheckSchedule \
  --action lambda:InvokeFunction \
  --principal events.amazonaws.com \
  --source-arn $(aws events describe-rule --name MakeHealthCheckSchedule --query 'Arn' --output text)

Create Target

Create target JSON file. This defines where EventBridge sends the event (to Lambda):

cat > targets.json << EOF
[
  {
    "Id": "1",
    "Arn": "$(aws lambda get-function --function-name MakeHealthCheck --query 'Configuration.FunctionArn' --output text)"
  }
]
EOF

Add target to the rule

aws events put-targets \
  --rule MakeHealthCheckSchedule \
  --targets file://targets.json

Updating the Lambda

As you change your Python code, redeploy by zipping and updating:

zip -r make-health-check.zip .

aws lambda update-function-code \
  --function-name MakeHealthCheck \
  --zip-file fileb://make-health-check.zip

Or use the Makefile…

Automate with Makefile

Automate all the manual steps with a Makefile:

# Makefile for building and deploying the weather-lambda project

.PHONY: install package deploy clean

install:
 pip install -r requirements.txt -t ./src

package:
 cd src && zip -r ../make-health-check.zip .

deploy: package
 aws lambda update-function-code \
  --function-name MakeHealthCheck \
  --zip-file fileb://make-health-check.zip

clean:
 rm -f make-health-check.zip
 rm -rf src/__pycache__

Now you can deploy with just:

make deploy

Cleaning Up

When you’re done, clean up resources to avoid charges.

Delete CloudWatch Event Rule and Targets

# First remove targets from the rule
aws events remove-targets \
  --rule MakeHealthCheckSchedule \
  --ids "1"

# Then delete the rule itself
aws events delete-rule \
  --name MakeHealthCheckSchedule

Delete lambda function

# Delete the function
aws lambda delete-function \
  --function-name MakeHealthCheck

Delete IAM Role and Policies

# First detach any managed policies from the role
aws iam detach-role-policy \
  --role-name MakeHealthCheckRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

# Delete any inline policies (if you added any)
aws iam list-role-policies --role-name MakeHealthCheckRole --query 'PolicyNames' --output text | \
while read -r policy; do
  aws iam delete-role-policy --role-name MakeHealthCheckRole --policy-name "$policy"
done

# Finally, delete the role
aws iam delete-role \
  --role-name MakeHealthCheckRole

Verify Cleanup

To make sure everything is cleaned up:

# Check if function still exists
aws lambda get-function --function-name MakeHealthCheck 2>&1 || echo "Function deleted successfully"

# Check if rule still exists
aws events describe-rule --name MakeHealthCheckSchedule 2>&1 || echo "Rule deleted successfully"

# Check if role still exists
aws iam get-role --role-name MakeHealthCheckRole 2>&1 || echo "Role deleted successfully"

If you’re unsure about any resources, you can use the AWS Console to search for “MakeHealthCheck” across all services to find any remaining resources.

One-liner to find related resources (optional)

aws resourcegroupstaggingapi get-resources --tag-filters Key=Name,Values=MakeHealthCheck

Conclusion: Serverless Scheduling Made Simple

By combining AWS Lambda, EventBridge, and Python, you’ve created a lightweight and scalable cron job — without ever worrying about servers, uptime, or instance cost.

This pattern is perfect for:

  • Health checks and monitoring
  • Scheduled API data ingestion
  • Log cleanup
  • Notifications and alerts

With a clean deployment pipeline using a Makefile, and proper IAM practices, your serverless cron architecture is robust, automated, and cloud-native.

comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy