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
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| 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
:
1
2
3
4
5
6
| 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
:
- Install them locally into
src/
:
1
| pip install -r requirements.txt -t ./src
|
1
| 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| cat > trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
|
Create Iam role
1
| aws iam create-role --role-name MakeHealthCheckRole --assume-role-policy-document file://trust-policy.json
|
Attach basic execution policy
1
| aws iam attach-role-policy --role-name MakeHealthCheckRole --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
|
Get role arn
1
| 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:
1
2
3
4
5
6
7
8
9
| 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:
1
2
3
| 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
1
2
3
4
5
6
| 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):
1
2
3
4
5
6
7
8
| 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
1
2
3
| aws events put-targets \
--rule MakeHealthCheckSchedule \
--targets file://targets.json
|
Updating the Lambda
As you change your Python code, redeploy by zipping and updating:
1
2
3
4
5
| 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 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:
Cleaning Up
When you’re done, clean up resources to avoid charges.
Delete CloudWatch Event Rule and Targets
1
2
3
4
5
6
7
8
| # 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
1
2
3
| # Delete the function
aws lambda delete-function \
--function-name MakeHealthCheck
|
Delete IAM Role and Policies
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 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:
1
2
3
4
5
6
7
8
| # 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)
1
| 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.