-
-
Notifications
You must be signed in to change notification settings - Fork 717
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: Optimizing AWS Lambda Documentation (#6991)
<!-- Thanks for creating a PR! To make it easier for reviewers and everyone else to understand what your changes relate to, please add some relevant content to the headings below. Feel free to ignore or delete sections that you don't think are relevant. Thank you! ❤️ --> ## About the changes <!-- Describe the changes introduced. What are they and why are they being introduced? Feel free to also add screenshots or steps to view the changes if they're visual. --> <!-- Does it close an issue? Multiple? --> Closes # <!-- (For internal contributors): Does it relate to an issue on public roadmap? --> <!-- Relates to [roadmap](https://github.com/orgs/Unleash/projects/10) item: # --> ### Important files <!-- PRs can contain a lot of changes, but not all changes are equally important. Where should a reviewer start looking to get an overview of the changes? Are any files particularly important? --> ## Discussion points <!-- Anything about the PR you'd like to discuss before it gets merged? Got any questions or doubts? --> Updates according to our revision doc for our horizontal content pieces.
- Loading branch information
1 parent
6b59b30
commit e9c4b47
Showing
1 changed file
with
81 additions
and
50 deletions.
There are no files selected for viewing
131 changes: 81 additions & 50 deletions
131
...s/feature-flag-tutorials/serverless/implementing-feature-flags-in-aws-lambda.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,142 +1,173 @@ | ||
--- | ||
title: How to implement feature flags in a serverless environment using AWS Lambda | ||
title: How to Implement Feature Flags in a Serverless Environment using AWS Lambda | ||
description: New to feature flags in serverless environments? This guide will walk you through a practical example using the Unleash Node.js SDK in AWS Lambda. | ||
slug: /feature-flag-tutorials/serverless/lambda | ||
--- | ||
|
||
For developers new to feature flags in serverless environments, this guide will walk you through practical examples using the [Unleash Node.js SDK](https://github.com/Unleash/unleash-client-node) in [AWS Lambda](https://aws.amazon.com/lambda/). These concepts can be easily adapted to other serverless solutions like [Google Cloud Functions](https://cloud.google.com/functions). Having feature flagging capabilities available inside of your serverless functions allows you to validate new parts of your serverless functions and stay in control of the feature exposure. | ||
Developers can add feature flagging capabilities to serverless functions and validate new parts of them. Leveraging feature flags gives you complete control over feature exposure and simplifies serverless function versioning management. | ||
|
||
For developers new to feature flags in serverless environments, this guide will walk you through practical examples using the [Unleash Node.js SDK](https://github.com/Unleash/unleash-client-node) in [AWS Lambda](https://aws.amazon.com/lambda/). Developers can easily adapt these concepts to other serverless solutions like [Google Cloud Functions](https://cloud.google.com/functions). | ||
|
||
## Scenarios for AWS Lambda feature flags | ||
|
||
- If you make a breaking change to a serverless function (e.g., new params), you usually need to create a new version with an appropriate URL routing scheme | ||
- But sometimes you may need to add a non-breaking change, signature-wise, that may still have unwanted side effects for some consumers | ||
- You may also want to make the feature change optional until it’s been thoroughly tested | ||
- Feature flags enable you to release a new function version in-place while controlling who gets exposed to the new feature | ||
- Benefits: | ||
- Simplifies serverless function version management | ||
- Allows you to test the change in the real world with a subset of API consumers before going 100% live | ||
- Simpler to manage than other forms of partial deployment (e.g., a canary rollout) | ||
|
||
![AWS Lambda connecting to Unleash](/img/lambda-architecture.png) | ||
|
||
## Step-by-step: Adding AWS Lambda feature flags | ||
|
||
## Step 1: Initialize the SDK. | ||
### Step 1: Initialize the SDK. | ||
|
||
In order to use any Unleash SDK, it needs to be initialized. This is when the SDK is configured with the necessary details to connect to the Unleash API. As part of initialization, the SDK downloads the most recent configuration from Unleash. The SDK also synchronizes with the Unleash API in the background, ensuring updates propagate to the Lambda functions. | ||
In order to use any Unleash SDK, it needs to be initialized. This is when the SDK is configured with the necessary details to connect to the Unleash API. As part of initialization, the SDK downloads the most recent configuration from Unleash. The SDK also synchronizes with the Unleash API in the background, ensuring updates propagate to the Lambda functions. | ||
|
||
It's essential to understand that the Unleash SDK should be initialized only once during the lifespan of a serverless function. This approach is critical to avoid the overhead of connecting to the external Unleash API with every invocation of an AWS Lambda. AWS Lambda is designed to reuse the same instance for multiple invocations, enabling the expensive initialization process to occur only during the Lambda's "cold start." Subsequent "warm" invocations can then leverage the SDK, which has been pre-initialized, with all feature flag configurations cached in memory. This ensures efficient operation by minimizing initialization overhead and enhancing performance. | ||
You should only initialize the Unleash SDK once during the lifespan of a serverless function. This avoids the overhead of connecting to the external Unleash API with every invocation of an AWS Lambda. | ||
|
||
You will also have to provide a [Unleash Server side API](https://docs.getunleash.io/how-to/how-to-create-api-tokens) Token as an environment variable for the AWS Lambda in order for the SDK to be able to connect to the Unleash API. | ||
Why? AWS Lambda is designed to reuse the same instance for multiple invocations, enabling the expensive initialization process to occur only during the Lambda's "cold start." Subsequent "warm" invocations can then leverage the SDK, which has been pre-initialized, with all feature flag configurations cached in memory. This ensures efficient operation by minimizing initialization overhead and enhancing performance. | ||
|
||
You’ll also need to provide an [Unleash Server side API Token](/how-to/how-to-create-api-tokens) as an environment variable for the AWS Lambda. This authorizes the SDK to connect to the Unleash API. | ||
|
||
```javascript | ||
import { startUnleash, InMemStorageProvider, destroyWithFlush } from 'unleash-client'; | ||
import { | ||
startUnleash, | ||
InMemStorageProvider, | ||
destroyWithFlush, | ||
} from "unleash-client"; | ||
let unleash; | ||
|
||
async function init() { | ||
if (!unleash) { | ||
unleash = await startUnleash({ | ||
url: 'https://sandbox.getunleash.io/enterprise/api/', | ||
appName: 'lambda-example-app', | ||
url: "<YOUR_UNLEASH_URL>", | ||
appName: "lambda-example-app", | ||
customHeaders: { | ||
authorization: process.env.API_TOKEN, | ||
}, | ||
storageProvider: new InMemStorageProvider(), | ||
}); | ||
unleash.on('initialized', () => console.log('[runtime] Unleash initialized')); | ||
} | ||
unleash.on("initialized", () => | ||
console.log("[runtime] Unleash initialized") | ||
); | ||
} | ||
} | ||
|
||
export const handler = async (event, context) => { | ||
// Only the first invocation will trigger SDK initialization. | ||
await init(); | ||
// Only the first invocation will trigger SDK initialization. | ||
await init(); | ||
return { | ||
statusCode: 200, | ||
body: {message: ``}, | ||
body: { message: `` }, | ||
}; | ||
}; | ||
``` | ||
|
||
## Step 2: Add graceful shutdown of the SDKs | ||
It’s important to handle the case of a Lambda shutting down in a graceful manner in order to preserve usage metrics. Fortunately, AWS Lambda receives a signal when AWS decides that the Lambda instance is not needed anymore. We can use this signal to make sure we send any outstanding cached usage metrics to Unleash API. | ||
### Step 2: Enable graceful shutdown of the SDKs | ||
|
||
You’ll need to handle graceful shutdown of the function in a way that preserves usage metrics when using AWS Lambda feature flags. | ||
|
||
The code below shows how we can add the listener in the “global” part of our function in order to destroy the Unleash SDK gracefully and make sure we flush any outstanding metrics back to the Unleash API. | ||
Fortunately, AWS Lambda receives a signal when AWS decides that the Lambda instance is not needed anymore. We can use this signal to make sure we send any outstanding cached usage metrics to Unleash API. | ||
|
||
The code below shows how to add the listener in the “global” part of our function in order to destroy the Unleash SDK gracefully. It also flushes any outstanding metrics back to the Unleash API. | ||
|
||
```javascript | ||
let unleash; | ||
|
||
process.on('SIGTERM', async () => { | ||
console.info('[runtime] SIGTERM received'); | ||
process.on("SIGTERM", async () => { | ||
console.info("[runtime] SIGTERM received"); | ||
|
||
if(unleash) { | ||
if (unleash) { | ||
await destroyWithFlush(); | ||
unleash = undefined; | ||
} | ||
|
||
process.exit(0) | ||
}); | ||
|
||
process.exit(0); | ||
}); | ||
``` | ||
|
||
### Step 3: Use the Unleash SDK for feature flagging | ||
### Step 3: Use the Unleash SDK for AWS Lambda feature flags | ||
|
||
Now that we have Unleash SDK properly initialized and we have a graceful shutdown hook, it's time to start taking advantage of feature flags in our serverless function. | ||
We’ve initialized the Unleash SDK and have code to handle graceful shutdown. It's time to start taking advantage of AWS Lambda feature flags. | ||
|
||
Luckily this is relatively straightforward, and we can just use the SDK as we would in any Node.js application. In the example below, we read the value of the “**simpleFlag**” and return the status as part of the JSON response from the function. | ||
Luckily this is straightforward. We can use the SDK as we would in any Node.js application. In the example below, we read the value of the **`simpleFlag`** flag and return the status as part of the JSON response from the function. | ||
|
||
```javascript | ||
import { startUnleash, InMemStorageProvider, destroyWithFlush } from 'unleash-client'; | ||
import { | ||
startUnleash, | ||
InMemStorageProvider, | ||
destroyWithFlush, | ||
} from "unleash-client"; | ||
|
||
let unleash; | ||
|
||
async function init() { | ||
if (!unleash) { | ||
console.log('[runtime] Starting unleash'); | ||
console.log("[runtime] Starting unleash"); | ||
unleash = await startUnleash({ | ||
url: 'https://sandbox.getunleash.io/enterprise/api/', | ||
appName: 'lambda-example-app', | ||
url: "https://sandbox.getunleash.io/enterprise/api/", | ||
appName: "lambda-example-app", | ||
customHeaders: { | ||
authorization: process.env.API_TOKEN, | ||
}, | ||
storageProvider: new InMemStorageProvider(), | ||
}); | ||
unleash.on('initialized', () => console.log('[runtime] Unleash initialized')); | ||
} | ||
unleash.on("initialized", () => | ||
console.log("[runtime] Unleash initialized") | ||
); | ||
} | ||
} | ||
|
||
process.on('SIGTERM', async () => { | ||
console.info('[runtime] SIGTERM received'); | ||
process.on("SIGTERM", async () => { | ||
console.info("[runtime] SIGTERM received"); | ||
|
||
if(unleash) { | ||
if (unleash) { | ||
await destroyWithFlush(); | ||
unleash = undefined; | ||
unleash = null; | ||
} | ||
process.exit(0) | ||
|
||
process.exit(0); | ||
}); | ||
|
||
export const handler = async (event, context) => { | ||
// Only the first invocation will trigger SDK initialization. | ||
// Only the first invocation will trigger SDK initialization. | ||
await init(); | ||
|
||
const isEnabled = unleash.isEnabled('simpleFlag') | ||
const isEnabled = unleash.isEnabled("simpleFlag"); | ||
|
||
return { | ||
statusCode: 200, | ||
body: {message: `Feature flag 'simpleFlag' is ${isEnabled ? 'enabled' : 'disabled'}`}, | ||
body: { | ||
message: `Feature flag 'simpleFlag' is ${ | ||
isEnabled ? "enabled" : "disabled" | ||
}`, | ||
}, | ||
}; | ||
}; | ||
``` | ||
|
||
In our Lambda setup we have enabled a [public function URL](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html), which allows us to trigger the function easily via the public URL of the function. | ||
When we set up our Lambda function, we gave it a [public function URL](https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html). This allows us to trigger the function easily via the URL that AWS Lambda generates. | ||
|
||
Example: | ||
|
||
```bash | ||
curl https://z5w5lkzlsozutfhaixbjsj27cm0dhnfh.lambda-url.eu-north-1.on.aws | ||
curl https://z5w5lkzlsozutfhaixbjsj27cm0dhnfh.lambda-url.eu-north-1.on.aws | ||
|
||
{"message":"Feature flag 'simpleFlag' is enabled"} | ||
``` | ||
|
||
## Conclusion | ||
|
||
Mastering feature flags in serverless? This guide demonstrated the surprisingly simple use of Unleash SDK. Remember, avoid initializing the SDK multiple times within your serverless function for smooth operation. | ||
## Scaling AWS Lambda feature flags | ||
|
||
If you plan to have thousands of RPS towards your lambda you should consider [Unleash Edge](https://docs.getunleash.io/understanding-unleash/proxy-hosting), a component built to scale your usage of Unleash. | ||
Mastering feature flags in serverless? This guide demonstrated the surprisingly simple use of Unleash SDK. Remember, avoid initializing the SDK multiple times within your serverless function for smooth operation. | ||
|
||
Need to scale your AWS Lambda function to thousands of requests per second (RPS)? Consider [Unleash Edge](/understanding-unleash/proxy-hosting), which uses edge computing to scale your Unleash usage. You can scale in any matter you see fit - either hosted entirely in your infrastructure on your own edge services or fully managed by Unleash. | ||
|
||
:::note Lambda latency | ||
:::note Lambda Latency | ||
|
||
If you care about latency and particularly faster cold starts you should take a look at [Low Latency Runtime](https://github.com/awslabs/llrt) (LTR) an experimental, lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. The team behind Unleash is super excited about this initiative. | ||
If you care about latency and particularly faster cold starts you should take a look at [Low Latency Runtime](https://github.com/awslabs/llrt) (LTR) an experimental, lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. The team behind Unleash is super excited about this initiative. | ||
|
||
::: | ||
::: |