Skip to content

Commit cbd93a1

Browse files
committed
Add resiliency documentation drafts
1 parent 133a1c8 commit cbd93a1

4 files changed

Lines changed: 285 additions & 20 deletions

File tree

‎bullet-proof-feature-flags.md‎

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# Bullet proof feature flags
2+
3+
**Keep your app running even if Reflag is temporarily unavailable.**
4+
5+
Reflag servers remain the primary source of truth. Even without any special setup, Reflag already behaves well in many failure cases: the Node SDK keeps using flag definitions it has already fetched in memory, and client-side SDKs can often continue from cached or previously bootstrapped flags when those are available.
6+
7+
The main remaining risk is startup. If the Reflag servers are down at the exact moment a new server process or client starts, and there is no saved snapshot or cached bootstrap data available yet, the browser or node process may have no local flag data to start from. In Node, this can happen after a deploy or scale-up event when a new process has not fetched flag definitions yet. In React and other client-side apps, this can happen when the client has no cached or bootstrapped flags and would otherwise need to make its first fetch from the Reflag servers.
8+
9+
Reflag runs a globally distributed server network with multiple redundancies. However, if you want maximum resilience in the exceedingly rare case of a Reflag outage, you should architect your application so it does not depend on live access to the Reflag servers during those startup paths.
10+
11+
The pattern is simple:
12+
13+
- on the server, use the Node SDK with `flagsFallbackProvider`
14+
- on the client, bootstrap flags from your server instead of doing an initial client-side fetch from the Reflag servers
15+
16+
Together, this gives you what we call **bullet proof feature flags**.
17+
18+
## What this means
19+
20+
With this setup:
21+
22+
- already-running Node processes keep using the flag definitions they already have in memory
23+
- newly-starting Node processes can initialize from the last saved snapshot
24+
- web clients can render from flags provided by your server
25+
- both server and client startup become highly resilient to Reflag availability issues
26+
27+
This is the most resilient way to use Reflag in production.
28+
29+
## The two parts of the setup
30+
31+
To get the full benefit, you need both server-side and client-side resilience.
32+
33+
### 1. Server-side resilience with `flagsFallbackProvider`
34+
35+
In the Node SDK, `flagsFallbackProvider` lets you persist the latest successfully fetched raw flag definitions to fallback storage such as:
36+
37+
- a local file
38+
- Redis
39+
- S3
40+
- a custom backend
41+
42+
On startup, the SDK still tries to fetch a live snapshot from Reflag first.
43+
44+
If that initial fetch fails, the SDK can load the last saved snapshot from the fallback provider instead. That means new Node processes can still initialize even if they cannot reach Reflag during startup.
45+
46+
After successfully fetching updated flag definitions, the SDK saves the latest snapshot back through the fallback provider so it stays current.
47+
48+
This protects **server startup**.
49+
50+
### 2. Client-side resilience with bootstrapped flags
51+
52+
For client-side applications, you should bootstrap flags from your server.
53+
54+
This means the client starts with flag data that your server already prepared, instead of making its own initial request to the Reflag servers.
55+
56+
This protects **client startup**.
57+
58+
Depending on your SDK, that looks like:
59+
60+
- **React**: `getFlagsForBootstrap()` + `ReflagBootstrappedProvider`
61+
- **React Native**: `ReflagBootstrappedProvider` with pre-fetched flags (following the React SDK bootstrapping patterns)
62+
- **Browser SDK**: `bootstrappedFlags`
63+
- **Vue SDK**: bootstrapped flags passed into the provider
64+
65+
## Why you need both
66+
67+
Using only one half of the setup improves reliability, but it does not give you the full bullet proof architecture.
68+
69+
### Only using `flagsFallbackProvider`
70+
71+
This helps your server start reliably.
72+
73+
But if your client app still depends on an initial fetch from the Reflag servers, then client startup can still be affected by a Reflag outage.
74+
75+
### Only using bootstrapped flags
76+
77+
This helps your client render reliably from server-provided flags.
78+
79+
But your server still needs to start successfully and produce those flags in the first place. Without a fallback provider, a newly-starting Node process may still fail to initialize if it cannot reach Reflag during startup.
80+
81+
### Using both together
82+
83+
This gives you the most resilient setup:
84+
85+
- the server can start from the last saved snapshot
86+
- the client can start from server-provided flags
87+
- fresh flag definitions are still fetched from Reflag whenever available
88+
89+
## Typical reliability flow
90+
91+
1. Your Node server starts and tries to fetch live flag definitions from Reflag.
92+
2. If that succeeds, it uses those definitions immediately.
93+
3. The server saves the latest definitions through `flagsFallbackProvider`.
94+
4. Your server generates bootstrapped flags for the client.
95+
5. The client starts from those bootstrapped flags instead of making an initial request to the Reflag servers.
96+
6. If a future Node process starts while Reflag is unavailable, it can load the last saved snapshot from the fallback provider and still initialize.
97+
7. Once Reflag becomes available again, the server resumes fetching the latest definitions and refreshes the saved snapshot.
98+
99+
## Recommended setup by SDK
100+
101+
### React
102+
103+
For React applications, the recommended resilient setup is:
104+
105+
- Node SDK on the server with `flagsFallbackProvider`
106+
- `getFlagsForBootstrap()` on the server
107+
- `ReflagBootstrappedProvider` in the React app
108+
109+
This means your React app does not depend on an initial client-side fetch from the Reflag servers on first render.
110+
111+
### Browser SDK
112+
113+
For non-React web apps using the Browser SDK:
114+
115+
- use the Node SDK on the server with `flagsFallbackProvider`
116+
- generate bootstrap data on the server
117+
- initialize the Browser SDK with `bootstrappedFlags`
118+
119+
This gives you the same resilience pattern: reliable server startup plus reliable client startup.
120+
121+
### Vue
122+
123+
For Vue applications:
124+
125+
- use the Node SDK on the server with `flagsFallbackProvider`
126+
- generate bootstrapped flags on the server
127+
- pass those bootstrapped flags into the Vue SDK provider
128+
129+
Again, the goal is to avoid depending on a live Reflag request during client initialization.
130+
131+
## Important clarification
132+
133+
This setup does not replace Reflag as the primary source of truth.
134+
135+
Your application should still fetch fresh flag definitions from Reflag whenever possible. What this setup changes is that your application becomes much less dependent on Reflag being reachable at the exact moment a Node process or browser session starts.
136+
137+
## Related docs
138+
139+
- Node SDK: fallback providers
140+
- React SDK: bootstrapping with `ReflagBootstrappedProvider`
141+
- Browser SDK: `bootstrappedFlags`
142+
- Vue SDK: bootstrapped flags

‎packages/browser-sdk/README.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,7 @@ const { isEnabled } = reflagClient.getFlag("voiceHuddle");
306306
await reflagClient.updateUser({ voiceHuddleOptIn: (!isEnabled).toString() });
307307
```
308308

309-
> [!NOTE]
310-
> `user`/`company` attributes are also stored remotely on the Reflag servers and will automatically be used to evaluate flag targeting if the page is refreshed.
309+
> [!NOTE] > `user`/`company` attributes are also stored remotely on the Reflag servers and will automatically be used to evaluate flag targeting if the page is refreshed.
311310
312311
### setContext()
313312

‎packages/node-sdk/README.md‎

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,7 @@ await client.initialize();
294294
The built-in S3 provider works out of the box using the AWS SDK's default credential chain and region resolution.
295295

296296
```typescript
297-
import {
298-
ReflagClient,
299-
createS3FlagsFallbackProvider,
300-
} from "@reflag/node-sdk";
297+
import { ReflagClient, createS3FlagsFallbackProvider } from "@reflag/node-sdk";
301298

302299
const client = new ReflagClient({
303300
secretKey: process.env.REFLAG_SECRET_KEY,
@@ -346,8 +343,7 @@ export const staticFallbackProvider: FlagsFallbackProvider = {
346343
};
347344
```
348345

349-
> [!NOTE]
350-
> `fallbackFlags` is deprecated. Prefer `flagsFallbackProvider` for startup fallback and outage recovery.
346+
> [!NOTE] > `fallbackFlags` is deprecated. Prefer `flagsFallbackProvider` for startup fallback and outage recovery.
351347
> `flagsFallbackProvider` is not used in offline mode.
352348
353349
## Bootstrapping client-side applications
@@ -545,18 +541,17 @@ a configuration file on disk or by passing options to the `ReflagClient`
545541
constructor. By default, the SDK searches for `reflag.config.json` in the
546542
current working directory.
547543

548-
| Option | Type | Description | Env Var |
549-
| --------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
550-
| `secretKey` | string | The secret key used for authentication with Reflag's servers. | REFLAG_SECRET_KEY |
551-
| `logLevel` | string | The log level for the SDK (e.g., `"DEBUG"`, `"INFO"`, `"WARN"`, `"ERROR"`). Default: `INFO` | REFLAG_LOG_LEVEL |
552-
| `offline` | boolean | Operate in offline mode. Default: `false`, except in tests it will default to `true` based off of the `TEST` env. var. In offline mode the SDK does not fetch from Reflag and does not use `flagsFallbackProvider`. | REFLAG_OFFLINE |
553-
| `apiBaseUrl` | string | The base API URL for the Reflag servers. | REFLAG_API_BASE_URL |
554-
| `flagOverrides` | Record<string, boolean> | An object specifying flag overrides for testing or local development. See [examples/express/app.test.ts](https://github.com/reflagcom/javascript/tree/main/packages/node-sdk/examples/express/app.test.ts) for how to use `flagOverrides` in tests. | REFLAG_FLAGS_ENABLED, REFLAG_FLAGS_DISABLED |
555-
| `flagsFallbackProvider` | `FlagsFallbackProvider` | Optional provider used to load and save raw flag definitions for fallback startup when the initial live fetch fails. Available only through the constructor. Ignored in offline mode. | - |
556-
| `configFile` | string | Load this config file from disk. Default: `reflag.config.json` | REFLAG_CONFIG_FILE |
557-
558-
> [!NOTE]
559-
> `REFLAG_FLAGS_ENABLED` and `REFLAG_FLAGS_DISABLED` are comma separated lists of flags which will be enabled or disabled respectively.
544+
| Option | Type | Description | Env Var |
545+
| ----------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
546+
| `secretKey` | string | The secret key used for authentication with Reflag's servers. | REFLAG_SECRET_KEY |
547+
| `logLevel` | string | The log level for the SDK (e.g., `"DEBUG"`, `"INFO"`, `"WARN"`, `"ERROR"`). Default: `INFO` | REFLAG_LOG_LEVEL |
548+
| `offline` | boolean | Operate in offline mode. Default: `false`, except in tests it will default to `true` based off of the `TEST` env. var. In offline mode the SDK does not fetch from Reflag and does not use `flagsFallbackProvider`. | REFLAG_OFFLINE |
549+
| `apiBaseUrl` | string | The base API URL for the Reflag servers. | REFLAG_API_BASE_URL |
550+
| `flagOverrides` | Record<string, boolean> | An object specifying flag overrides for testing or local development. See [examples/express/app.test.ts](https://github.com/reflagcom/javascript/tree/main/packages/node-sdk/examples/express/app.test.ts) for how to use `flagOverrides` in tests. | REFLAG_FLAGS_ENABLED, REFLAG_FLAGS_DISABLED |
551+
| `flagsFallbackProvider` | `FlagsFallbackProvider` | Optional provider used to load and save raw flag definitions for fallback startup when the initial live fetch fails. Available only through the constructor. Ignored in offline mode. | - |
552+
| `configFile` | string | Load this config file from disk. Default: `reflag.config.json` | REFLAG_CONFIG_FILE |
553+
554+
> [!NOTE] > `REFLAG_FLAGS_ENABLED` and `REFLAG_FLAGS_DISABLED` are comma separated lists of flags which will be enabled or disabled respectively.
560555
561556
`reflag.config.json` example:
562557

0 commit comments

Comments
 (0)