-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathdata_system.rb
More file actions
243 lines (219 loc) · 8.21 KB
/
data_system.rb
File metadata and controls
243 lines (219 loc) · 8.21 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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# frozen_string_literal: true
require 'ldclient-rb/interfaces/data_system'
require 'ldclient-rb/config'
require 'ldclient-rb/impl/data_system/polling'
require 'ldclient-rb/impl/data_system/streaming'
module LaunchDarkly
#
# Configuration for LaunchDarkly's data acquisition strategy.
#
# This module provides factory methods for creating data system configurations.
#
module DataSystem
#
# Builder for the data system configuration.
#
class ConfigBuilder
def initialize
@initializers = nil
@primary_synchronizer = nil
@secondary_synchronizer = nil
@fdv1_fallback_synchronizer = nil
@data_store_mode = LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY
@data_store = nil
end
#
# Sets the initializers for the data system.
#
# @param initializers [Array<Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Initializer>]
# Array of builder procs that take sdk_key and Config and return an Initializer
# @return [ConfigBuilder] self for chaining
#
def initializers(initializers)
@initializers = initializers
self
end
#
# Sets the synchronizers for the data system.
#
# @param primary [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer] Builder proc that takes sdk_key and Config and returns the primary Synchronizer
# @param secondary [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# Builder proc that takes sdk_key and Config and returns the secondary Synchronizer
# @return [ConfigBuilder] self for chaining
#
def synchronizers(primary, secondary = nil)
@primary_synchronizer = primary
@secondary_synchronizer = secondary
self
end
#
# Configures the SDK with a fallback synchronizer that is compatible with
# the Flag Delivery v1 API.
#
# @param fallback [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer]
# Builder proc that takes sdk_key and Config and returns the fallback Synchronizer
# @return [ConfigBuilder] self for chaining
#
def fdv1_compatible_synchronizer(fallback)
@fdv1_fallback_synchronizer = fallback
self
end
#
# Sets the data store configuration for the data system.
#
# @param data_store [LaunchDarkly::Interfaces::FeatureStore] The data store
# @param store_mode [Symbol] The store mode
# @return [ConfigBuilder] self for chaining
#
def data_store(data_store, store_mode)
@data_store = data_store
@data_store_mode = store_mode
self
end
#
# Builds the data system configuration.
#
# @return [DataSystemConfig]
# @raise [ArgumentError] if configuration is invalid
#
def build
if @secondary_synchronizer && @primary_synchronizer.nil?
raise ArgumentError, "Primary synchronizer must be set if secondary is set"
end
DataSystemConfig.new(
initializers: @initializers,
primary_synchronizer: @primary_synchronizer,
secondary_synchronizer: @secondary_synchronizer,
data_store_mode: @data_store_mode,
data_store: @data_store,
fdv1_fallback_synchronizer: @fdv1_fallback_synchronizer
)
end
end
#
# Returns a builder proc for creating a polling data source.
# This is a building block that can be used with {ConfigBuilder#initializers}
# or {ConfigBuilder#synchronizers} to create custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns a polling data source
#
def self.polling_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder.new(sdk_key, config).build
end
end
#
# Returns a builder proc for creating an FDv1 fallback polling data source.
# This is a building block that can be used with {ConfigBuilder#fdv1_compatible_synchronizer}
# to provide FDv1 compatibility in custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns an FDv1 polling data source
#
def self.fdv1_fallback_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder.new(sdk_key, config).build
end
end
#
# Returns a builder proc for creating a streaming data source.
# This is a building block that can be used with {ConfigBuilder#synchronizers}
# to create custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns a streaming data source
#
def self.streaming_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder.new(sdk_key, config).build
end
end
#
# Default is LaunchDarkly's recommended flag data acquisition strategy.
#
# Currently, it operates a two-phase method for obtaining data: first, it
# requests data from LaunchDarkly's global CDN. Then, it initiates a
# streaming connection to LaunchDarkly's Flag Delivery services to
# receive real-time updates.
#
# If the streaming connection is interrupted for an extended period of
# time, the SDK will automatically fall back to polling the global CDN
# for updates.
#
# @return [ConfigBuilder]
#
def self.default
polling_builder = polling_ds_builder
streaming_builder = streaming_ds_builder
fallback = fdv1_fallback_ds_builder
builder = ConfigBuilder.new
builder.initializers([polling_builder])
builder.synchronizers(streaming_builder, polling_builder)
builder.fdv1_compatible_synchronizer(fallback)
builder
end
#
# Streaming configures the SDK to efficiently stream flag/segment data
# in the background, allowing evaluations to operate on the latest data
# with no additional latency.
#
# @return [ConfigBuilder]
#
def self.streaming
streaming_builder = streaming_ds_builder
fallback = fdv1_fallback_ds_builder
builder = ConfigBuilder.new
builder.synchronizers(streaming_builder)
builder.fdv1_compatible_synchronizer(fallback)
builder
end
#
# Polling configures the SDK to regularly poll an endpoint for
# flag/segment data in the background. This is less efficient than
# streaming, but may be necessary in some network environments.
#
# @return [ConfigBuilder]
#
def self.polling
polling_builder = polling_ds_builder
fallback = fdv1_fallback_ds_builder
builder = ConfigBuilder.new
builder.synchronizers(polling_builder)
builder.fdv1_compatible_synchronizer(fallback)
builder
end
#
# Custom returns a builder suitable for creating a custom data
# acquisition strategy. You may configure how the SDK uses a Persistent
# Store, how the SDK obtains an initial set of data, and how the SDK
# keeps data up-to-date.
#
# @return [ConfigBuilder]
#
def self.custom
ConfigBuilder.new
end
#
# Daemon configures the SDK to read from a persistent store integration
# that is populated by Relay Proxy or other SDKs. The SDK will not connect
# to LaunchDarkly. In this mode, the SDK never writes to the data store.
#
# @param store [Object] The persistent store
# @return [ConfigBuilder]
#
def self.daemon(store)
custom.data_store(store, LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY)
end
#
# PersistentStore is similar to default, with the addition of a persistent
# store integration. Before data has arrived from LaunchDarkly, the SDK is
# able to evaluate flags using data from the persistent store. Once fresh
# data is available, the SDK will no longer read from the persistent store,
# although it will keep it up-to-date.
#
# @param store [Object] The persistent store
# @return [ConfigBuilder]
#
def self.persistent_store(store)
default.data_store(store, LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_WRITE)
end
end
end