launchdarkly-server-sdk 6.2.5 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -2
- data/lib/ldclient-rb/config.rb +203 -43
- data/lib/ldclient-rb/context.rb +487 -0
- data/lib/ldclient-rb/evaluation_detail.rb +85 -26
- data/lib/ldclient-rb/events.rb +185 -146
- data/lib/ldclient-rb/flags_state.rb +25 -14
- data/lib/ldclient-rb/impl/big_segments.rb +117 -0
- data/lib/ldclient-rb/impl/context.rb +96 -0
- data/lib/ldclient-rb/impl/context_filter.rb +145 -0
- data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
- data/lib/ldclient-rb/impl/evaluator.rb +428 -132
- data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
- data/lib/ldclient-rb/impl/evaluator_helpers.rb +50 -0
- data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
- data/lib/ldclient-rb/impl/event_sender.rb +6 -6
- data/lib/ldclient-rb/impl/event_summarizer.rb +68 -0
- data/lib/ldclient-rb/impl/event_types.rb +78 -0
- data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +92 -28
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +212 -0
- data/lib/ldclient-rb/impl/integrations/redis_impl.rb +165 -32
- data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +40 -0
- data/lib/ldclient-rb/impl/model/clause.rb +39 -0
- data/lib/ldclient-rb/impl/model/feature_flag.rb +213 -0
- data/lib/ldclient-rb/impl/model/preprocessed_data.rb +64 -0
- data/lib/ldclient-rb/impl/model/segment.rb +126 -0
- data/lib/ldclient-rb/impl/model/serialization.rb +54 -44
- data/lib/ldclient-rb/impl/repeating_task.rb +47 -0
- data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
- data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
- data/lib/ldclient-rb/impl/util.rb +62 -1
- data/lib/ldclient-rb/in_memory_store.rb +2 -2
- data/lib/ldclient-rb/integrations/consul.rb +9 -2
- data/lib/ldclient-rb/integrations/dynamodb.rb +47 -2
- data/lib/ldclient-rb/integrations/file_data.rb +108 -0
- data/lib/ldclient-rb/integrations/redis.rb +43 -3
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +594 -0
- data/lib/ldclient-rb/integrations/test_data.rb +213 -0
- data/lib/ldclient-rb/integrations/util/store_wrapper.rb +14 -9
- data/lib/ldclient-rb/integrations.rb +2 -51
- data/lib/ldclient-rb/interfaces.rb +151 -1
- data/lib/ldclient-rb/ldclient.rb +175 -133
- data/lib/ldclient-rb/memoized_value.rb +1 -1
- data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
- data/lib/ldclient-rb/polling.rb +22 -41
- data/lib/ldclient-rb/reference.rb +274 -0
- data/lib/ldclient-rb/requestor.rb +7 -7
- data/lib/ldclient-rb/stream.rb +9 -9
- data/lib/ldclient-rb/util.rb +11 -17
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +2 -4
- metadata +49 -23
- data/lib/ldclient-rb/event_summarizer.rb +0 -55
- data/lib/ldclient-rb/file_data_source.rb +0 -314
- data/lib/ldclient-rb/impl/event_factory.rb +0 -126
- data/lib/ldclient-rb/newrelic.rb +0 -17
- data/lib/ldclient-rb/redis_store.rb +0 -88
- data/lib/ldclient-rb/user_filter.rb +0 -52
@@ -12,7 +12,7 @@ module LaunchDarkly
|
|
12
12
|
# @raise [ArgumentError] if `variation_index` or `reason` is not of the correct type
|
13
13
|
def initialize(value, variation_index, reason)
|
14
14
|
raise ArgumentError.new("variation_index must be a number") if !variation_index.nil? && !(variation_index.is_a? Numeric)
|
15
|
-
raise ArgumentError.new("reason must be an EvaluationReason")
|
15
|
+
raise ArgumentError.new("reason must be an EvaluationReason") unless reason.is_a? EvaluationReason
|
16
16
|
@value = value
|
17
17
|
@variation_index = variation_index
|
18
18
|
@reason = reason
|
@@ -70,20 +70,20 @@ module LaunchDarkly
|
|
70
70
|
class EvaluationReason
|
71
71
|
# Value for {#kind} indicating that the flag was off and therefore returned its configured off value.
|
72
72
|
OFF = :OFF
|
73
|
-
|
74
|
-
# Value for {#kind} indicating that the flag was on but the
|
73
|
+
|
74
|
+
# Value for {#kind} indicating that the flag was on but the context did not match any targets or rules.
|
75
75
|
FALLTHROUGH = :FALLTHROUGH
|
76
|
-
|
77
|
-
# Value for {#kind} indicating that the
|
76
|
+
|
77
|
+
# Value for {#kind} indicating that the context key was specifically targeted for this flag.
|
78
78
|
TARGET_MATCH = :TARGET_MATCH
|
79
|
-
|
80
|
-
# Value for {#kind} indicating that the
|
79
|
+
|
80
|
+
# Value for {#kind} indicating that the context matched one of the flag's rules.
|
81
81
|
RULE_MATCH = :RULE_MATCH
|
82
|
-
|
82
|
+
|
83
83
|
# Value for {#kind} indicating that the flag was considered off because it had at least one
|
84
84
|
# prerequisite flag that either was off or did not return the desired variation.
|
85
85
|
PREREQUISITE_FAILED = :PREREQUISITE_FAILED
|
86
|
-
|
86
|
+
|
87
87
|
# Value for {#kind} indicating that the flag could not be evaluated, e.g. because it does not exist
|
88
88
|
# or due to an unexpected error. In this case the result value will be the application default value
|
89
89
|
# that the caller passed to the client. Check {#error_kind} for more details on the problem.
|
@@ -100,8 +100,8 @@ module LaunchDarkly
|
|
100
100
|
# a rule specified a nonexistent variation. An error message will always be logged in this case.
|
101
101
|
ERROR_MALFORMED_FLAG = :MALFORMED_FLAG
|
102
102
|
|
103
|
-
# Value for {#error_kind} indicating that the caller passed `nil` for the
|
104
|
-
#
|
103
|
+
# Value for {#error_kind} indicating that the caller passed `nil` for the context parameter, or the
|
104
|
+
# context was invalid.
|
105
105
|
ERROR_USER_NOT_SPECIFIED = :USER_NOT_SPECIFIED
|
106
106
|
|
107
107
|
# Value for {#error_kind} indicating that an unexpected exception stopped flag evaluation. An error
|
@@ -110,27 +110,42 @@ module LaunchDarkly
|
|
110
110
|
|
111
111
|
# Indicates the general category of the reason. Will always be one of the class constants such
|
112
112
|
# as {#OFF}.
|
113
|
+
# @return [Symbol]
|
113
114
|
attr_reader :kind
|
114
115
|
|
115
116
|
# The index of the rule that was matched (0 for the first rule in the feature flag). If
|
116
117
|
# {#kind} is not {#RULE_MATCH}, this will be `nil`.
|
118
|
+
# @return [Integer|nil]
|
117
119
|
attr_reader :rule_index
|
118
120
|
|
119
121
|
# A unique string identifier for the matched rule, which will not change if other rules are added
|
120
122
|
# or deleted. If {#kind} is not {#RULE_MATCH}, this will be `nil`.
|
123
|
+
# @return [String]
|
121
124
|
attr_reader :rule_id
|
122
125
|
|
123
126
|
# A boolean or nil value representing if the rule or fallthrough has an experiment rollout.
|
127
|
+
# @return [Boolean|nil]
|
124
128
|
attr_reader :in_experiment
|
125
129
|
|
126
130
|
# The key of the prerequisite flag that did not return the desired variation. If {#kind} is not
|
127
131
|
# {#PREREQUISITE_FAILED}, this will be `nil`.
|
132
|
+
# @return [String]
|
128
133
|
attr_reader :prerequisite_key
|
129
134
|
|
130
135
|
# A value indicating the general category of error. This should be one of the class constants such
|
131
136
|
# as {#ERROR_FLAG_NOT_FOUND}. If {#kind} is not {#ERROR}, it will be `nil`.
|
137
|
+
# @return [Symbol]
|
132
138
|
attr_reader :error_kind
|
133
139
|
|
140
|
+
# Describes the validity of Big Segment information, if and only if the flag evaluation required
|
141
|
+
# querying at least one Big Segment. Otherwise it returns `nil`. Possible values are defined by
|
142
|
+
# {BigSegmentsStatus}.
|
143
|
+
#
|
144
|
+
# Big Segments are a specific kind of context segments. For more information, read the LaunchDarkly
|
145
|
+
# documentation: https://docs.launchdarkly.com/home/users/big-segments
|
146
|
+
# @return [Symbol]
|
147
|
+
attr_reader :big_segments_status
|
148
|
+
|
134
149
|
# Returns an instance whose {#kind} is {#OFF}.
|
135
150
|
# @return [EvaluationReason]
|
136
151
|
def self.off
|
@@ -161,9 +176,9 @@ module LaunchDarkly
|
|
161
176
|
# @return [EvaluationReason]
|
162
177
|
# @raise [ArgumentError] if `rule_index` is not a number or `rule_id` is not a string
|
163
178
|
def self.rule_match(rule_index, rule_id, in_experiment=false)
|
164
|
-
raise ArgumentError.new("rule_index must be a number")
|
179
|
+
raise ArgumentError.new("rule_index must be a number") unless rule_index.is_a? Numeric
|
165
180
|
raise ArgumentError.new("rule_id must be a string") if !rule_id.nil? && !(rule_id.is_a? String) # in test data, ID could be nil
|
166
|
-
|
181
|
+
|
167
182
|
if in_experiment
|
168
183
|
er = new(:RULE_MATCH, rule_index, rule_id, nil, nil, true)
|
169
184
|
else
|
@@ -178,7 +193,7 @@ module LaunchDarkly
|
|
178
193
|
# @return [EvaluationReason]
|
179
194
|
# @raise [ArgumentError] if `prerequisite_key` is nil or not a string
|
180
195
|
def self.prerequisite_failed(prerequisite_key)
|
181
|
-
raise ArgumentError.new("prerequisite_key must be a string")
|
196
|
+
raise ArgumentError.new("prerequisite_key must be a string") unless prerequisite_key.is_a? String
|
182
197
|
new(:PREREQUISITE_FAILED, nil, nil, prerequisite_key, nil)
|
183
198
|
end
|
184
199
|
|
@@ -188,7 +203,7 @@ module LaunchDarkly
|
|
188
203
|
# @return [EvaluationReason]
|
189
204
|
# @raise [ArgumentError] if `error_kind` is not a symbol
|
190
205
|
def self.error(error_kind)
|
191
|
-
raise ArgumentError.new("error_kind must be a symbol")
|
206
|
+
raise ArgumentError.new("error_kind must be a symbol") unless error_kind.is_a? Symbol
|
192
207
|
e = @@error_instances[error_kind]
|
193
208
|
e.nil? ? make_error(error_kind) : e
|
194
209
|
end
|
@@ -196,11 +211,13 @@ module LaunchDarkly
|
|
196
211
|
def ==(other)
|
197
212
|
if other.is_a? EvaluationReason
|
198
213
|
@kind == other.kind && @rule_index == other.rule_index && @rule_id == other.rule_id &&
|
199
|
-
@prerequisite_key == other.prerequisite_key && @error_kind == other.error_kind
|
214
|
+
@prerequisite_key == other.prerequisite_key && @error_kind == other.error_kind &&
|
215
|
+
@big_segments_status == other.big_segments_status
|
200
216
|
elsif other.is_a? Hash
|
201
217
|
@kind.to_s == other[:kind] && @rule_index == other[:ruleIndex] && @rule_id == other[:ruleId] &&
|
202
218
|
@prerequisite_key == other[:prerequisiteKey] &&
|
203
|
-
(other[:errorKind] == @error_kind.nil? ? nil : @error_kind.to_s)
|
219
|
+
(other[:errorKind] == @error_kind.nil? ? nil : @error_kind.to_s) &&
|
220
|
+
(other[:bigSegmentsStatus] == @big_segments_status.nil? ? nil : @big_segments_status.to_s)
|
204
221
|
end
|
205
222
|
end
|
206
223
|
|
@@ -242,7 +259,7 @@ module LaunchDarkly
|
|
242
259
|
# enabled for a flag and the application called variation_detail, or 2. experimentation is
|
243
260
|
# enabled for an evaluation. We can't reuse these hashes because an application could call
|
244
261
|
# as_json and then modify the result.
|
245
|
-
case @kind
|
262
|
+
ret = case @kind
|
246
263
|
when :RULE_MATCH
|
247
264
|
if @in_experiment
|
248
265
|
{ kind: @kind, ruleIndex: @rule_index, ruleId: @rule_id, inExperiment: @in_experiment }
|
@@ -262,6 +279,10 @@ module LaunchDarkly
|
|
262
279
|
else
|
263
280
|
{ kind: @kind }
|
264
281
|
end
|
282
|
+
unless @big_segments_status.nil?
|
283
|
+
ret[:bigSegmentsStatus] = @big_segments_status
|
284
|
+
end
|
285
|
+
ret
|
265
286
|
end
|
266
287
|
|
267
288
|
# Same as {#as_json}, but converts the JSON structure into a string.
|
@@ -285,27 +306,36 @@ module LaunchDarkly
|
|
285
306
|
@prerequisite_key
|
286
307
|
when :errorKind
|
287
308
|
@error_kind.nil? ? nil : @error_kind.to_s
|
309
|
+
when :bigSegmentsStatus
|
310
|
+
@big_segments_status.nil? ? nil : @big_segments_status.to_s
|
288
311
|
else
|
289
312
|
nil
|
290
313
|
end
|
291
314
|
end
|
292
315
|
|
293
|
-
|
316
|
+
def with_big_segments_status(big_segments_status)
|
317
|
+
return self if @big_segments_status == big_segments_status
|
318
|
+
EvaluationReason.new(@kind, @rule_index, @rule_id, @prerequisite_key, @error_kind, @in_experiment, big_segments_status)
|
319
|
+
end
|
294
320
|
|
295
|
-
|
321
|
+
#
|
322
|
+
# Constructor that sets all properties. Applications should not normally use this constructor,
|
323
|
+
# but should use class methods like {#off} to avoid creating unnecessary instances.
|
324
|
+
#
|
325
|
+
def initialize(kind, rule_index, rule_id, prerequisite_key, error_kind, in_experiment=nil,
|
326
|
+
big_segments_status = nil)
|
296
327
|
@kind = kind.to_sym
|
297
328
|
@rule_index = rule_index
|
298
329
|
@rule_id = rule_id
|
299
|
-
@rule_id.freeze
|
330
|
+
@rule_id.freeze unless rule_id.nil?
|
300
331
|
@prerequisite_key = prerequisite_key
|
301
|
-
@prerequisite_key.freeze
|
332
|
+
@prerequisite_key.freeze unless prerequisite_key.nil?
|
302
333
|
@error_kind = error_kind
|
303
334
|
@in_experiment = in_experiment
|
335
|
+
@big_segments_status = big_segments_status
|
304
336
|
end
|
305
337
|
|
306
|
-
private_class_method
|
307
|
-
|
308
|
-
def self.make_error(error_kind)
|
338
|
+
private_class_method def self.make_error(error_kind)
|
309
339
|
new(:ERROR, nil, nil, nil, error_kind)
|
310
340
|
end
|
311
341
|
|
@@ -318,7 +348,36 @@ module LaunchDarkly
|
|
318
348
|
ERROR_FLAG_NOT_FOUND => make_error(ERROR_FLAG_NOT_FOUND),
|
319
349
|
ERROR_MALFORMED_FLAG => make_error(ERROR_MALFORMED_FLAG),
|
320
350
|
ERROR_USER_NOT_SPECIFIED => make_error(ERROR_USER_NOT_SPECIFIED),
|
321
|
-
ERROR_EXCEPTION => make_error(ERROR_EXCEPTION)
|
351
|
+
ERROR_EXCEPTION => make_error(ERROR_EXCEPTION),
|
322
352
|
}
|
323
353
|
end
|
354
|
+
|
355
|
+
#
|
356
|
+
# Defines the possible values of {EvaluationReason#big_segments_status}.
|
357
|
+
#
|
358
|
+
module BigSegmentsStatus
|
359
|
+
#
|
360
|
+
# Indicates that the Big Segment query involved in the flag evaluation was successful, and
|
361
|
+
# that the segment state is considered up to date.
|
362
|
+
#
|
363
|
+
HEALTHY = :HEALTHY
|
364
|
+
|
365
|
+
#
|
366
|
+
# Indicates that the Big Segment query involved in the flag evaluation was successful, but
|
367
|
+
# that the segment state may not be up to date.
|
368
|
+
#
|
369
|
+
STALE = :STALE
|
370
|
+
|
371
|
+
#
|
372
|
+
# Indicates that Big Segments could not be queried for the flag evaluation because the SDK
|
373
|
+
# configuration did not include a Big Segment store.
|
374
|
+
#
|
375
|
+
NOT_CONFIGURED = :NOT_CONFIGURED
|
376
|
+
|
377
|
+
#
|
378
|
+
# Indicates that the Big Segment query involved in the flag evaluation failed, for instance
|
379
|
+
# due to a database error.
|
380
|
+
#
|
381
|
+
STORE_ERROR = :STORE_ERROR
|
382
|
+
end
|
324
383
|
end
|