• HOME
  • INTEGRATIONS
  • SDKS
  • GUIDES
  • API DOCS
No results for ""
EXPAND ALL
CLOSE
launchdarkly.com

EDIT ON GITHUB

Using LaunchDarkly in serverless functions

Read time: 4 minutes
Last edited: Jul 14, 2020

Overview

This guide provides best practice advice for using LaunchDarkly with Function-as-a-Service (FaaS), or serverless, platforms, such as AWS Lambda. While most uses of serverless architecture require no extra configuration, some apps may benefit from additional configuration to ensure consistent high performance.

In this article, we’ll start with the assertion that you have already chosen to use serverless functions in your application architecture.

Concepts

To use this guide effectively, you should understand the following concepts:

Serverless

Serverless computing is a cloud computing model where cloud provider runs the server and dynamically manages the allocation of machine resources.

Function-as-a-Service (FaaS)

FaaS services are serverless computing services that allow customers to develop, run, and manage small units of functionality. These units can be developed and deployed independently, and then connected later to form a single app. This model contrasts with the more traditional software development model, in which functions are compiled together into a single monolithic unit before deployment.

Using LaunchDarkly in a serverless infrastructure

FaaS platforms are popular because they let developers code in the languages they know while vastly reducing the effort required to create and manage production infrastructure.

If you're considering using LaunchDarkly in a serverless or containerised app, the LaunchDarkly SDK in its default configuration will have no significant performance impact in a serverless environment.

However, if your app is sensitive to initialization performance, consider configuring the LaunchDarkly SDK to use a persistent local flag store. A local flag store can increase initialization speed.

How the SDKs balance performance

Each LaunchDarkly SDK is designed to have minimal impact on application performance. In its default configuration, its impact occurs almost entirely in the app's initialization phase.

Here's how the SDK interacts with your app:

  1. While the app starts, the SDK connects to LaunchDarkly and downloads the project's flags to an in-memory store. This network connection is held open while the app runs so that flag updates are received immediately.
  2. Once the app has finished initializing, the in-memory flag store is used for flag evaluation functions such as variation. These functions run instantly, with no need to wait for network I/O.

Most apps are architected with the expectation that initialization takes a miniscule amount of the app's total runtime. Apps with serverless or containerized architectures may have different expectations.

During normal operation with relatively consistent load, the underlying platform uses long-lived runtime instances, or Execution Contexts for each function or container. As in most other app architectures, the initialization time has insignificant impact on performance.

However, if a serverless app receives a sudden flood of requests, the platform may start extra runtime instances to handle the requests that arrive. Any additional latency in the initialization phase has extra impact, reducing performance and increasing the number of instances required to handle the load.

Most serverless apps never deal with this kind of sudden traffic increase, nor are they as sensitive to latency in the initial request. Those apps should use the default LaunchDarkly configuration. This configuration is displayed in Example 1.

If your app has higher performance needs and is more likely to receive sudden traffic floods, or if the LaunchDarkly project has such a large and complex set of flags that initialization time is noticeably affected, then you can take additional steps to mitigate that. This configuration is displayed in Example 2.

The examples below are service-agnostic
Both of the examples below use AWS Lambda, but you can use this approach for other FaaS platforms as well.

Option 1: Use the SDK as normal

For smaller workloads, you can use the LaunchDarkly SDK as you normally would.

Here is a code sample that shows how to evaluate a feature flag with the NodeJS runtime in AWS Lambda:

1var LaunchDarkly = require('launchdarkly-node-server-sdk');
2var ldClient = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY);
3var ready = ldClient.waitUntilReady();
4
5exports.handler = (event, context, callback) => {
6
7 ready.then(() => {
8 /*
9 ...evaluate your flags and do your work here...
10 */
11 callback();
12 }, callback);
13}

This approach may take longer for the runtime to initialize, but after initialization the requests handled by that runtime instance will suffer no performance hit.

This approach should function for the majority of serverless applications.

Option 2: Use a persistent feature store

If your app often sees high levels of concurrency or sensitivity to cold starts, you may need to reduce the initialization time that LaunchDarkly takes. You can do this by setting up a persistent feature store to serve flag values locally.

In this configuration, the LaunchDarkly SDK no longer downloads the project's entire flag set for later evaluation. Instead, it connects to the configured feature store at initialization time, then queries the feature store for each flag evaluation call.

To learn more, read Using a persistent feature store.

The example below is a five-step process to configure a feature store for more consistent

  1. You can use a cloud-local storage service to act as a flag store.
  2. You can use a dedicated AWS Lambda function to update the flag store when a flag configuration changes.
  3. You can use an AWS API Gateway endpoint to give the Lambda function a consistent HTTPS URL.
  4. You can create a LaunchDarkly webhook to send flag changes to the API Gateway URL.
  5. You can configure the LaunchDarkly SDK to read flags from the persistent flag store.

Most LaunchDarkly server-side SDKs can use a Redis database for persistent feature storage. AWS ElastiCache is compatible with Redis, and we use it as an example here, but other services will work as well.

An ElastiCache cluster composed of three small nodes should be sufficient for all but the largest LaunchDarkly projects.

This dedicated AWS Lambda function, built on the NodeJS runtime, connects to the LaunchDarkly network and updates the ElastiCache feature store.

We configure it using the RedisFeatureStore method. The AWS Lambda function built on the NodeJS runtime could like this:

1var LaunchDarkly = require('launchdarkly-node-server-sdk');
2
3exports.handler = (event, context, callback) => {
4 setTimeout(() => {
5 var redisConfig = {
6 port: process.env.ELASTICACHE_PORT,
7 host: process.env.ELASTICACHE_ENDPOINT
8 };
9 var store = new LaunchDarkly.RedisFeatureStore(redisConfig));
10
11 var ldConfig = {
12 feature_store: store
13 };
14 var ldClient = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY, ldConfig);
15
16 ldClient.once('ready', () => {
17 ldClient.close();
18 callback(null, 'store updated');
19 });
20 }, 2000); // initialize after some delay to ensure that LD caches have been purged
21}

In this example, we initialize the LaunchDarkly SDK inside the handler. By initializing the SDK in this way, we update the ElastiCache store with the latest flag state. The webhook lets this function know that an updated state is available.

After the store update function has been created, it needs a URL so it can be triggered by an HTTPS call. To provide this URL, create an API Gateway endpoint.

Now that both the feature store and the store update function are ready, add a webhook to the LaunchDarkly Project. To learn more, read Webhooks.

After you set up the webhook, every configuration change made to the LaunchDarkly project's flags triggers an update in the cloud-hosted feature store.

Creation of a LaunchDarkly webhook which will send flag updates to a Lambda function
Creation of a LaunchDarkly webhook which will send flag updates to a Lambda function

Finally, with the persistent feature store active and continuously updated, you can configure the app to use the feature store instead of connecting to LaunchDarkly's servers.

To learn more, read Using a persistent feature store without connecting to LaunchDarkly.

The app code retains the same structure as the example in Option 1 above, but with additional configuration to point at the feature store and enable LDD mode.

1var LaunchDarkly = require('launchdarkly-node-server-sdk');
2
3var redisConfig = {
4 port: process.env.ELASTICACHE_PORT,
5 host: process.env.ELASTICACHE_ENDPOINT
6};
7var store = new LaunchDarkly.RedisFeatureStore(redisConfig);
8
9var ldConfig = {
10 feature_store: store,
11 use_ldd: true
12};
13
14var ldClient = LaunchDarkly.init(process.env.LAUNCHDARKLY_SDK_KEY, {ldConfig});
15
16exports.handler = (event, context, callback) => {
17 /*
18 ...evaluate your flags and do your work here...
19 */
20 callback();
21};

Conclusion

In most cases, LaunchDarkly works in serverless environments without additional configuration. If you need more support, however, the methods outlined above can help.

If you have more questions or need further assistance, get in touch by contacting Support.