launchdarkly-server-sdk 6.2.5 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|