-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.ts
More file actions
138 lines (120 loc) · 4.83 KB
/
index.ts
File metadata and controls
138 lines (120 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import {
SplitFactory,
PluggableStorage,
ErrorLogger
} from "@splitsoftware/splitio-browserjs";
import { Synchronizer } from "@splitsoftware/splitio-sync-tools";
import { SplitStorageWrapper } from "./SplitStorageWrapper";
// In order for the workers runtime to find the class that implements
// our Durable Object namespace, we must export it from the root module.
export { SplitStorage } from "./SplitStorage";
/**
* Worker script.
*
* Implemented using the new "Module Worker" syntax (See https://developers.cloudflare.com/workers/learning/migrating-to-module-workers).
* This new syntax is required when using Durable Objects, because they are implemented by classes, and those classes need to be exported.
*
* To be deployed, this worker must be configured with a Durable Object namespace bindings call 'SplitStorage', which is already configured
* in the wrangler.toml file. Take into account that Durable Objects are only available with a Workers paid subscription.
*/
export default {
// Handle HTTP incoming requests
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
switch (url.pathname) {
// Use Split SDK to evaluate a feature flag. Request example `/get-treatment?key=some_key&feature-flag=some_feature_flag_name`
case "/get-treatment":
return handleGetTreatmentRequest(url, env);
// Synchronize your Split Storage, same as scheduled requests
case "/sync":
return handleSynchronization(env);
// Clean up all data from your Split Storage. SDK instances will evaluate to 'control'
case "/delete-all":
const durableObjectStub = getSplitStorage(env);
return durableObjectStub.fetch("https://dummy-url/deleteAll");
default:
return new Response("Not found", { status: 404 });
}
},
// Handle scheduled requests by a cron trigger, use to synchronize your Split Storage periodically
async scheduled(
controller: ScheduledController,
env: Env,
ctx: ExecutionContext
) {
return handleSynchronization(env);
}
};
interface Env {
SplitStorage: DurableObjectNamespace;
}
// Server-side SDK key is required for Synchronizer and sufficient for JS Browser SDK
const sdkKey = "<YOUR-SERVER-SIDE-SDK-KEY>";
// Get reference to Split Storage durable object
function getSplitStorage(env: Env) {
// Here we use Split SDK key as durable object name, but any name can be used.
// Actually, multiple SDKs with different SDK keys could access the same durable object,
// as long as they set different storage prefixes to avoid data collisions.
const id = env.SplitStorage.idFromName(sdkKey);
return env.SplitStorage.get(id);
}
// Use Split SDK to evaluate a feature flag
async function handleGetTreatmentRequest(url: URL, env: Env) {
const key = url.searchParams.get("key");
if (!key) return new Response("No key provided", { status: 400 });
const featureFlagName = url.searchParams.get("feature-flag");
if (!featureFlagName)
return new Response("No feature flag name provided", { status: 400 });
// SDK instances are created in 'consumer_partial' mode, which access
// the Split Storage to get the rollout plan data for evaluations
const factory = SplitFactory({
core: {
authorizationKey: sdkKey,
key
},
mode: "consumer_partial",
storage: PluggableStorage({
wrapper: SplitStorageWrapper(getSplitStorage(env))
}),
// Disable or keep only ERROR log level in production, to minimize performance impact
debug: ErrorLogger()
});
const client = factory.client();
// Wait until the SDK is ready or times out
try {
await client.whenReady();
} catch (e) {
// SDK timed out. Treatment evaluations will fall back to 'control'.
// This should never happen if SplitStorage durable object binding is properly configured.
}
// Async evaluation, because it access the rollout plan from the Split Storage
const treatment = await client.getTreatment(featureFlagName);
// Flush data to Split backend. But not await, in order to reduce response latency
client.destroy();
// Do something with the treatment
return new Response(`Treatment: ${treatment}`);
}
// Synchronize rollout plan data into Split Storage durable object
async function handleSynchronization(env: Env) {
const synchronizer = new Synchronizer({
core: {
authorizationKey: sdkKey
},
storage: {
type: "PLUGGABLE",
wrapper: SplitStorageWrapper(getSplitStorage(env))
},
// Disable or keep only ERROR log level in production, to minimize performance impact
debug: "ERROR"
});
try {
await new Promise<void>((res, rej) => {
synchronizer.execute(error => (error ? rej(error) : res()));
});
return new Response("Synchronization finished");
} catch (error) {
return new Response(`Synchronization failed with error: ${error}`, {
status: 500
});
}
}