Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions examples/aws-redis-serverless/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# <!--name--> AWS Serverless Redis

An example of deploying a Redis serverless cache using [Amazon ElastiCache Serverless](https://aws.amazon.com/elasticache/serverless/).

This example demonstrates the new `serverless` option in SST's Redis component, which automatically scales based on usage and offers pay-per-use pricing.

## Key Features

- **Serverless Redis**: No instance management required
- **Automatic Scaling**: Scales based on usage
- **Pay-per-use**: Only pay for what you consume
- **Simplified VPC**: No NAT Gateway required for serverless
- **Same Client Interface**: Uses the same Redis client as traditional clusters

## Get started

1. **Clone and deploy**

```bash
git clone https://github.com/sst/sst
cd sst/examples/aws-redis-serverless
npm install
sst deploy
```

2. **Test the Redis connection**

Once deployed, you can invoke the function to test the Redis connection:

```bash
sst invoke MyApp
```

## Usage

The serverless Redis is created with default limits:

```ts title="sst.config.ts" {4-7}
const redis = new sst.aws.Redis("MyRedis", {
vpc,
serverless: {
dataStorage: { maximum: 10, unit: "GB" },
ecpuPerSeconds: { maximum: 5000 }
}
});
```

You can also enable serverless mode with defaults:

```ts title="sst.config.ts" {3}
const redis = new sst.aws.Redis("MyRedis", {
vpc,
serverless: true
});
```

The client code remains exactly the same:

```ts title="index.ts" {4-6,11-12}
import { Cluster } from "ioredis";
import { Resource } from "sst";

const client = new Cluster([{
host: Resource.MyRedis.host,
port: Resource.MyRedis.port,
}], {
redisOptions: {
tls: { checkServerIdentity: () => undefined },
username: Resource.MyRedis.username,
password: Resource.MyRedis.password
}
});
```

## Architecture

```
┌──────────────┐ ┌─────────────────────┐
│ Lambda │───▶│ ElastiCache │
│ Function │ │ Serverless Redis │
└──────────────┘ └─────────────────────┘
│ │
└──────────────────────┘
VPC Network
```

## Cost

Serverless Redis pricing is based on:
- **Data Storage**: Per GB stored
- **ElastiCache Processing Units (ECPUs)**: Per second of processing

Example cost for light usage:
- Storage: 1 GB = ~$0.125/month
- ECPUs: 1000 ECPU/second = ~$0.0034/hour

This is significantly cheaper than traditional instances for variable workloads.

## Differences from Traditional Redis

| Traditional Redis | Serverless Redis |
|-------------------|------------------|
| Fixed instance costs | Pay-per-use pricing |
| Manual scaling | Automatic scaling |
| Requires NAT Gateway | Simplified networking |
| Cluster/non-cluster modes | Simplified configuration |
| Instance-based limits | Usage-based limits |
30 changes: 30 additions & 0 deletions examples/aws-redis-serverless/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Cluster } from "ioredis";
import { Resource } from "sst";

const client = new Cluster(
[
{
host: Resource.MyRedis.host,
port: Resource.MyRedis.port,
},
],
{
redisOptions: {
tls: {
checkServerIdentity: () => undefined,
},
username: Resource.MyRedis.username,
password: Resource.MyRedis.password,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the code when creating a serverless redis we don't generate a password, i don't know if this is on purpose but this line gives the error: Property password does not exist on type

},
}
);

export async function handler() {
await client.set("foo", `bar-serverless-${Date.now()}`);
return {
statusCode: 200,
body: JSON.stringify({
foo: await client.get("foo"),
}),
};
}
17 changes: 17 additions & 0 deletions examples/aws-redis-serverless/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "aws-redis-serverless",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ioredis": "^5.4.1",
"sst": "latest"
}
}
16 changes: 16 additions & 0 deletions examples/aws-redis-serverless/sst-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* This file is auto-generated by SST. Do not edit. */
/* tslint:disable */
/* eslint-disable */
/* deno-fmt-ignore-file */

declare module "sst" {
export interface Resource {
"MyVpc": {
"type": "sst.aws.Vpc"
}
}
}
/// <reference path="sst-env.d.ts" />

import "sst"
export {}
28 changes: 28 additions & 0 deletions examples/aws-redis-serverless/sst.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/// <reference path="./.sst/platform/config.d.ts" />

export default $config({
app(input) {
return {
name: "aws-redis-serverless",
removal: input?.stage === "production" ? "retain" : "remove",
home: "aws",
};
},
async run() {
// Serverless Redis doesn't require NAT Gateways
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even though serverless redis doesn't require a NAT gateway, in my testings i had to add it otherwise the lambda function wasn't accesible while sst gave this warning:

Warning: One or more functions are deployed in the "vpc-04554314d7b657e92" VPC, which does not have a NAT gateway. As a result, these functions cannot access the internet. If your functions need int ernet access, enable it by setting the "nat" prop on the "Vpc" component.

const vpc = new sst.aws.Vpc("MyVpc");
const redis = new sst.aws.Redis("MyRedis", {
vpc,
serverless: {
dataStorage: { maximum: 10, unit: "GB" },
ecpuPerSeconds: { maximum: 5000 }
}
});
new sst.aws.Function("MyApp", {
handler: "index.handler",
url: true,
vpc,
link: [redis],
});
},
});
Loading