Skip to content

Instantly share code, notes, and snippets.

@hackmajoris
Last active February 6, 2024 10:31
Show Gist options
  • Save hackmajoris/e9a4badd38fc24d7596ce32bc1187310 to your computer and use it in GitHub Desktop.
Save hackmajoris/e9a4badd38fc24d7596ce32bc1187310 to your computer and use it in GitHub Desktop.
Start and Stop RDS Scheduler with Lambda and CDK TypeScript Stack
import { Handler } from 'aws-lambda';
import * as AWS from 'aws-sdk';
const rds = new AWS.RDS();
enum InstanceStatus {
STOPPED = 'stopped',
AVAILABLE = 'available',
}
export const handler: Handler = async () => {
try {
const instances = await rds.describeDBInstances().promise();
console.log('Found instances: ', instances.DBInstances);
if (instances.DBInstances) {
for (const instance of instances.DBInstances) {
const identifier = instance.DBInstanceIdentifier!;
const instanceStatus = instance.DBInstanceStatus!;
console.log(`${identifier} status: `, instanceStatus);
if (instanceStatus === InstanceStatus.STOPPED) {
console.log(`Starting DB Instance with identifier: ${identifier}`);
await rds.startDBInstance({ DBInstanceIdentifier: identifier }).promise();
} else {
console.log(`Stopping DB Instance with identifier: ${identifier}`);
await rds.stopDBInstance({ DBInstanceIdentifier: identifier }).promise();
}
}
}
const describeClusters = await rds.describeDBClusters().promise();
console.log('Found clusters: ', describeClusters.DBClusters);
if (describeClusters.DBClusters) {
for (const cluster of describeClusters.DBClusters) {
const identifier = cluster.DBClusterIdentifier!;
const instanceStatus = cluster.Status!;
console.log(`${cluster.DBClusterIdentifier} status: `, cluster.Status);
if (cluster.Status === InstanceStatus.STOPPED) {
console.log(`Starting DB Cluster with identifier: ${identifier}`);
await rds.startDBCluster({ DBClusterIdentifier: identifier }).promise();
} else {
console.log(`Stopping DB Cluster with identifier: ${identifier}`);
await rds.stopDBCluster({ DBClusterIdentifier: identifier }).promise();
}
}
}
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ success: true }),
isBase64Encoded: false,
};
} catch (error) {
console.error(error);
return {
statusCode: 500,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ error: error }),
isBase64Encoded: false,
};
}
};
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as events from 'aws-cdk-lib/aws-events';
import { aws_events_targets, CfnOutput, NestedStack } from "aws-cdk-lib";
import { Construct } from "constructs";
import * as iam from 'aws-cdk-lib/aws-iam';
export class StartStopRdsStack extends cdk.NestedStack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Create the Lambda function to start RDS
const startRdsInstancesLambda = new lambda.Function(this, 'psb-rds-start-lambda', {
runtime: lambda.Runtime.NODEJS_14_X,
functionName: 'psb-rds-start-lambda',
code: lambda.Code.fromAsset("start-stop-rds-lambda"),
handler: "index.handler",
environment: {
"tag": "some-tag",
"info": "Shared function for starting RDS instances"
}
});
// Assign role to lambda to access RDS
startRdsInstancesLambda.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: [
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"rds:StartDBInstance",
"rds:StartDBCluster",
"rds:StopDBInstance",
"rds:StopDBCluster"
],
resources: ["*"]
}));
// Create the CloudWatch Event rule for starting RDS every day at 7 AM
const startRdsInstancesRule = new events.Rule(this, 'psb-start-rds-instances-rule', {
schedule: events.Schedule.cron({
minute: '0',
hour: '7',
month: '*',
weekDay: 'MON-FRI'
}),
});
startRdsInstancesRule.addTarget(new aws_events_targets.LambdaFunction(startRdsInstancesLambda));
// Create the CloudWatch Event rule for stopping RDS every day at 18 PM
const stopRdsInstancesRule = new events.Rule(this, 'psb-stop-rds-instances-rule', {
schedule: events.Schedule.cron({
minute: '0',
hour: '18',
month: '*',
weekDay: 'MON-FRI'
}),
});
stopRdsInstancesRule.addTarget(new aws_events_targets.LambdaFunction(startRdsInstancesLambda));
}
}
@hackmajoris
Copy link
Author

hackmajoris commented Jan 23, 2023

Creating a schedule for your Amazon RDS instances and clusters can help you save money on running costs, and also ensure that your database is only running when it's needed.
It applies mostly on not-prod environments, where you have multiple RDS instances and the cost of running them becomes a problem.

There are several ways to schedule your RDS instances, such as using the AWS Management Console, the AWS Command Line Interface (CLI), or a third-party tool. However, one of the most effective ways to schedule your RDS instances is by using AWS Lambda and CloudWatch Events.

In the above example, everything is created via CDK stack in TypeScript. The Lambda will stop all the instances and clusters which will be found in the AWS account and the region specified in the CDK config. The RDS instances and clusters could be filtered using the DescribeDBInstances/DescribeDBClusters APIs in order to apply the scheduler on a specific instance/cluster.

The scheduler is set to run every day, except the Weekend at 7 AM for starting, and 18 PM for stopping them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment