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
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'ldclient-rb/impl/integrations/test_data/test_data_source'
|
2
|
+
require 'ldclient-rb/impl/model/feature_flag'
|
3
|
+
require 'ldclient-rb/impl/model/segment'
|
4
|
+
require 'ldclient-rb/integrations/test_data/flag_builder'
|
5
|
+
|
6
|
+
require 'concurrent/atomics'
|
7
|
+
|
8
|
+
module LaunchDarkly
|
9
|
+
module Integrations
|
10
|
+
#
|
11
|
+
# A mechanism for providing dynamically updatable feature flag state in a simplified form to an SDK
|
12
|
+
# client in test scenarios.
|
13
|
+
#
|
14
|
+
# Unlike {LaunchDarkly::Integrations::FileData}, this mechanism does not use any external resources. It
|
15
|
+
# provides only the data that the application has put into it using the {#update} method.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# td = LaunchDarkly::Integrations::TestData.data_source
|
19
|
+
# td.update(td.flag("flag-key-1").variation_for_all(true))
|
20
|
+
# config = LaunchDarkly::Config.new(data_source: td)
|
21
|
+
# client = LaunchDarkly::LDClient.new('sdkKey', config)
|
22
|
+
# # flags can be updated at any time:
|
23
|
+
# td.update(td.flag("flag-key-2")
|
24
|
+
# .variation_for_key("user", some-user-key", true)
|
25
|
+
# .fallthrough_variation(false))
|
26
|
+
#
|
27
|
+
# The above example uses a simple boolean flag, but more complex configurations are possible using
|
28
|
+
# the methods of the {FlagBuilder} that is returned by {#flag}. {FlagBuilder}
|
29
|
+
# supports many of the ways a flag can be configured on the LaunchDarkly dashboard, but does not
|
30
|
+
# currently support 1. rule operators other than "in" and "not in", or 2. percentage rollouts.
|
31
|
+
#
|
32
|
+
# If the same `TestData` instance is used to configure multiple `LDClient` instances,
|
33
|
+
# any changes made to the data will propagate to all of the `LDClient`s.
|
34
|
+
#
|
35
|
+
# @since 6.3.0
|
36
|
+
#
|
37
|
+
class TestData
|
38
|
+
# Creates a new instance of the test data source.
|
39
|
+
#
|
40
|
+
# @return [TestData] a new configurable test data source
|
41
|
+
def self.data_source
|
42
|
+
self.new
|
43
|
+
end
|
44
|
+
|
45
|
+
# @private
|
46
|
+
def initialize
|
47
|
+
@flag_builders = Hash.new
|
48
|
+
@current_flags = Hash.new
|
49
|
+
@current_segments = Hash.new
|
50
|
+
@instances = Array.new
|
51
|
+
@instances_lock = Concurrent::ReadWriteLock.new
|
52
|
+
@lock = Concurrent::ReadWriteLock.new
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Called internally by the SDK to determine what arguments to pass to call
|
57
|
+
# You do not need to call this method.
|
58
|
+
#
|
59
|
+
# @private
|
60
|
+
def arity
|
61
|
+
2
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Called internally by the SDK to associate this test data source with an {@code LDClient} instance.
|
66
|
+
# You do not need to call this method.
|
67
|
+
#
|
68
|
+
# @private
|
69
|
+
def call(_, config)
|
70
|
+
impl = LaunchDarkly::Impl::Integrations::TestData::TestDataSource.new(config.feature_store, self)
|
71
|
+
@instances_lock.with_write_lock { @instances.push(impl) }
|
72
|
+
impl
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Creates or copies a {FlagBuilder} for building a test flag configuration.
|
77
|
+
#
|
78
|
+
# If this flag key has already been defined in this `TestData` instance, then the builder
|
79
|
+
# starts with the same configuration that was last provided for this flag.
|
80
|
+
#
|
81
|
+
# Otherwise, it starts with a new default configuration in which the flag has `true` and
|
82
|
+
# `false` variations, is `true` for all contexts when targeting is turned on and
|
83
|
+
# `false` otherwise, and currently has targeting turned on. You can change any of those
|
84
|
+
# properties, and provide more complex behavior, using the {FlagBuilder} methods.
|
85
|
+
#
|
86
|
+
# Once you have set the desired configuration, pass the builder to {#update}.
|
87
|
+
#
|
88
|
+
# @param key [String] the flag key
|
89
|
+
# @return [FlagBuilder] a flag configuration builder
|
90
|
+
#
|
91
|
+
def flag(key)
|
92
|
+
existing_builder = @lock.with_read_lock { @flag_builders[key] }
|
93
|
+
if existing_builder.nil? then
|
94
|
+
FlagBuilder.new(key).boolean_flag
|
95
|
+
else
|
96
|
+
existing_builder.clone
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Updates the test data with the specified flag configuration.
|
102
|
+
#
|
103
|
+
# This has the same effect as if a flag were added or modified on the LaunchDarkly dashboard.
|
104
|
+
# It immediately propagates the flag change to any `LDClient` instance(s) that you have
|
105
|
+
# already configured to use this `TestData`. If no `LDClient` has been started yet,
|
106
|
+
# it simply adds this flag to the test data which will be provided to any `LDClient` that
|
107
|
+
# you subsequently configure.
|
108
|
+
#
|
109
|
+
# Any subsequent changes to this {FlagBuilder} instance do not affect the test data,
|
110
|
+
# unless you call {#update} again.
|
111
|
+
#
|
112
|
+
# @param flag_builder [FlagBuilder] a flag configuration builder
|
113
|
+
# @return [TestData] the TestData instance
|
114
|
+
#
|
115
|
+
def update(flag_builder)
|
116
|
+
new_flag = nil
|
117
|
+
@lock.with_write_lock do
|
118
|
+
@flag_builders[flag_builder.key] = flag_builder
|
119
|
+
version = 0
|
120
|
+
flag_key = flag_builder.key.to_sym
|
121
|
+
if @current_flags[flag_key] then
|
122
|
+
version = @current_flags[flag_key][:version]
|
123
|
+
end
|
124
|
+
new_flag = Impl::Model.deserialize(FEATURES, flag_builder.build(version+1))
|
125
|
+
@current_flags[flag_key] = new_flag
|
126
|
+
end
|
127
|
+
update_item(FEATURES, new_flag)
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Copies a full feature flag data model object into the test data.
|
133
|
+
#
|
134
|
+
# It immediately propagates the flag change to any `LDClient` instance(s) that you have already
|
135
|
+
# configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds
|
136
|
+
# this flag to the test data which will be provided to any LDClient that you subsequently
|
137
|
+
# configure.
|
138
|
+
#
|
139
|
+
# Use this method if you need to use advanced flag configuration properties that are not supported by
|
140
|
+
# the simplified {FlagBuilder} API. Otherwise it is recommended to use the regular {flag}/{update}
|
141
|
+
# mechanism to avoid dependencies on details of the data model.
|
142
|
+
#
|
143
|
+
# You cannot make incremental changes with {flag}/{update} to a flag that has been added in this way;
|
144
|
+
# you can only replace it with an entirely new flag configuration.
|
145
|
+
#
|
146
|
+
# @param flag [Hash] the flag configuration
|
147
|
+
# @return [TestData] the TestData instance
|
148
|
+
#
|
149
|
+
def use_preconfigured_flag(flag)
|
150
|
+
use_preconfigured_item(FEATURES, flag, @current_flags)
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Copies a full segment data model object into the test data.
|
155
|
+
#
|
156
|
+
# It immediately propagates the change to any `LDClient` instance(s) that you have already
|
157
|
+
# configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds
|
158
|
+
# this segment to the test data which will be provided to any LDClient that you subsequently
|
159
|
+
# configure.
|
160
|
+
#
|
161
|
+
# This method is currently the only way to inject segment data, since there is no builder
|
162
|
+
# API for segments. It is mainly intended for the SDK's own tests of segment functionality,
|
163
|
+
# since application tests that need to produce a desired evaluation state could do so more easily
|
164
|
+
# by just setting flag values.
|
165
|
+
#
|
166
|
+
# @param segment [Hash] the segment configuration
|
167
|
+
# @return [TestData] the TestData instance
|
168
|
+
#
|
169
|
+
def use_preconfigured_segment(segment)
|
170
|
+
use_preconfigured_item(SEGMENTS, segment, @current_segments)
|
171
|
+
end
|
172
|
+
|
173
|
+
private def use_preconfigured_item(kind, item, current)
|
174
|
+
item = Impl::Model.deserialize(kind, item)
|
175
|
+
key = item.key.to_sym
|
176
|
+
@lock.with_write_lock do
|
177
|
+
old_item = current[key]
|
178
|
+
unless old_item.nil? then
|
179
|
+
data = item.as_json
|
180
|
+
data[:version] = old_item.version + 1
|
181
|
+
item = Impl::Model.deserialize(kind, data)
|
182
|
+
end
|
183
|
+
current[key] = item
|
184
|
+
end
|
185
|
+
update_item(kind, item)
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
private def update_item(kind, item)
|
190
|
+
@instances_lock.with_read_lock do
|
191
|
+
@instances.each do | instance |
|
192
|
+
instance.upsert(kind, item)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# @private
|
198
|
+
def make_init_data
|
199
|
+
@lock.with_read_lock do
|
200
|
+
{
|
201
|
+
FEATURES => @current_flags.clone,
|
202
|
+
SEGMENTS => @current_segments.clone,
|
203
|
+
}
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def closed_instance(instance)
|
209
|
+
@instances_lock.with_write_lock { @instances.delete(instance) }
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -4,6 +4,11 @@ require "ldclient-rb/expiring_cache"
|
|
4
4
|
|
5
5
|
module LaunchDarkly
|
6
6
|
module Integrations
|
7
|
+
#
|
8
|
+
# Support code that may be helpful in creating integrations.
|
9
|
+
#
|
10
|
+
# @since 5.5.0
|
11
|
+
#
|
7
12
|
module Util
|
8
13
|
#
|
9
14
|
# CachingStoreWrapper is a partial implementation of the {LaunchDarkly::Interfaces::FeatureStore}
|
@@ -17,7 +22,7 @@ module LaunchDarkly
|
|
17
22
|
#
|
18
23
|
class CachingStoreWrapper
|
19
24
|
include LaunchDarkly::Interfaces::FeatureStore
|
20
|
-
|
25
|
+
|
21
26
|
#
|
22
27
|
# Creates a new store wrapper instance.
|
23
28
|
#
|
@@ -44,7 +49,7 @@ module LaunchDarkly
|
|
44
49
|
@core.init_internal(all_data)
|
45
50
|
@inited.make_true
|
46
51
|
|
47
|
-
|
52
|
+
unless @cache.nil?
|
48
53
|
@cache.clear
|
49
54
|
all_data.each do |kind, items|
|
50
55
|
@cache[kind] = items_if_not_deleted(items)
|
@@ -56,15 +61,15 @@ module LaunchDarkly
|
|
56
61
|
end
|
57
62
|
|
58
63
|
def get(kind, key)
|
59
|
-
|
64
|
+
unless @cache.nil?
|
60
65
|
cache_key = item_cache_key(kind, key)
|
61
66
|
cached = @cache[cache_key] # note, item entries in the cache are wrapped in an array so we can cache nil values
|
62
|
-
return item_if_not_deleted(cached[0])
|
67
|
+
return item_if_not_deleted(cached[0]) unless cached.nil?
|
63
68
|
end
|
64
69
|
|
65
70
|
item = @core.get_internal(kind, key)
|
66
71
|
|
67
|
-
|
72
|
+
unless @cache.nil?
|
68
73
|
@cache[cache_key] = [item]
|
69
74
|
end
|
70
75
|
|
@@ -72,20 +77,20 @@ module LaunchDarkly
|
|
72
77
|
end
|
73
78
|
|
74
79
|
def all(kind)
|
75
|
-
|
80
|
+
unless @cache.nil?
|
76
81
|
items = @cache[all_cache_key(kind)]
|
77
|
-
return items
|
82
|
+
return items unless items.nil?
|
78
83
|
end
|
79
84
|
|
80
85
|
items = items_if_not_deleted(@core.get_all_internal(kind))
|
81
|
-
@cache[all_cache_key(kind)] = items
|
86
|
+
@cache[all_cache_key(kind)] = items unless @cache.nil?
|
82
87
|
items
|
83
88
|
end
|
84
89
|
|
85
90
|
def upsert(kind, item)
|
86
91
|
new_state = @core.upsert_internal(kind, item)
|
87
92
|
|
88
|
-
|
93
|
+
unless @cache.nil?
|
89
94
|
@cache[item_cache_key(kind, item[:key])] = [new_state]
|
90
95
|
@cache.delete(all_cache_key(kind))
|
91
96
|
end
|
@@ -1,55 +1,6 @@
|
|
1
1
|
require "ldclient-rb/integrations/consul"
|
2
2
|
require "ldclient-rb/integrations/dynamodb"
|
3
|
+
require "ldclient-rb/integrations/file_data"
|
3
4
|
require "ldclient-rb/integrations/redis"
|
5
|
+
require "ldclient-rb/integrations/test_data"
|
4
6
|
require "ldclient-rb/integrations/util/store_wrapper"
|
5
|
-
|
6
|
-
module LaunchDarkly
|
7
|
-
#
|
8
|
-
# Tools for connecting the LaunchDarkly client to other software.
|
9
|
-
#
|
10
|
-
module Integrations
|
11
|
-
#
|
12
|
-
# Integration with [Consul](https://www.consul.io/).
|
13
|
-
#
|
14
|
-
# Note that in order to use this integration, you must first install the gem `diplomat`.
|
15
|
-
#
|
16
|
-
# @since 5.5.0
|
17
|
-
#
|
18
|
-
module Consul
|
19
|
-
# code is in ldclient-rb/impl/integrations/consul_impl
|
20
|
-
end
|
21
|
-
|
22
|
-
#
|
23
|
-
# Integration with [DynamoDB](https://aws.amazon.com/dynamodb/).
|
24
|
-
#
|
25
|
-
# Note that in order to use this integration, you must first install one of the AWS SDK gems: either
|
26
|
-
# `aws-sdk-dynamodb`, or the full `aws-sdk`.
|
27
|
-
#
|
28
|
-
# @since 5.5.0
|
29
|
-
#
|
30
|
-
module DynamoDB
|
31
|
-
# code is in ldclient-rb/impl/integrations/dynamodb_impl
|
32
|
-
end
|
33
|
-
|
34
|
-
#
|
35
|
-
# Integration with [Redis](https://redis.io/).
|
36
|
-
#
|
37
|
-
# Note that in order to use this integration, you must first install the `redis` and `connection-pool`
|
38
|
-
# gems.
|
39
|
-
#
|
40
|
-
# @since 5.5.0
|
41
|
-
#
|
42
|
-
module Redis
|
43
|
-
# code is in ldclient-rb/impl/integrations/redis_impl
|
44
|
-
end
|
45
|
-
|
46
|
-
#
|
47
|
-
# Support code that may be helpful in creating integrations.
|
48
|
-
#
|
49
|
-
# @since 5.5.0
|
50
|
-
#
|
51
|
-
module Util
|
52
|
-
# code is in ldclient-rb/integrations/util/
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "observer"
|
1
2
|
|
2
3
|
module LaunchDarkly
|
3
4
|
#
|
@@ -120,7 +121,8 @@ module LaunchDarkly
|
|
120
121
|
#
|
121
122
|
# The client has its own standard implementation, which uses either a streaming connection or
|
122
123
|
# polling depending on your configuration. Normally you will not need to use another one
|
123
|
-
# except for testing purposes.
|
124
|
+
# except for testing purposes. Two such test fixtures are {LaunchDarkly::Integrations::FileData}
|
125
|
+
# and {LaunchDarkly::Integrations::TestData}.
|
124
126
|
#
|
125
127
|
module DataSource
|
126
128
|
#
|
@@ -149,5 +151,153 @@ module LaunchDarkly
|
|
149
151
|
def stop
|
150
152
|
end
|
151
153
|
end
|
154
|
+
|
155
|
+
module BigSegmentStore
|
156
|
+
#
|
157
|
+
# Returns information about the overall state of the store. This method will be called only
|
158
|
+
# when the SDK needs the latest state, so it should not be cached.
|
159
|
+
#
|
160
|
+
# @return [BigSegmentStoreMetadata]
|
161
|
+
#
|
162
|
+
def get_metadata
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Queries the store for a snapshot of the current segment state for a specific context.
|
167
|
+
#
|
168
|
+
# The context_hash is a base64-encoded string produced by hashing the context key as defined by
|
169
|
+
# the Big Segments specification; the store implementation does not need to know the details
|
170
|
+
# of how this is done, because it deals only with already-hashed keys, but the string can be
|
171
|
+
# assumed to only contain characters that are valid in base64.
|
172
|
+
#
|
173
|
+
# The return value should be either a Hash, or nil if the context is not referenced in any big
|
174
|
+
# segments. Each key in the Hash is a "segment reference", which is how segments are
|
175
|
+
# identified in Big Segment data. This string is not identical to the segment key-- the SDK
|
176
|
+
# will add other information. The store implementation should not be concerned with the
|
177
|
+
# format of the string. Each value in the Hash is true if the context is explicitly included in
|
178
|
+
# the segment, false if the context is explicitly excluded from the segment-- and is not also
|
179
|
+
# explicitly included (that is, if both an include and an exclude existed in the data, the
|
180
|
+
# include would take precedence). If the context's status in a particular segment is undefined,
|
181
|
+
# there should be no key or value for that segment.
|
182
|
+
#
|
183
|
+
# This Hash may be cached by the SDK, so it should not be modified after it is created. It
|
184
|
+
# is a snapshot of the segment membership state at one point in time.
|
185
|
+
#
|
186
|
+
# @param context_hash [String]
|
187
|
+
# @return [Hash] true/false values for Big Segments that reference this context
|
188
|
+
#
|
189
|
+
def get_membership(context_hash)
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Performs any necessary cleanup to shut down the store when the client is being shut down.
|
194
|
+
#
|
195
|
+
# @return [void]
|
196
|
+
#
|
197
|
+
def stop
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
#
|
202
|
+
# Values returned by {BigSegmentStore#get_metadata}.
|
203
|
+
#
|
204
|
+
class BigSegmentStoreMetadata
|
205
|
+
def initialize(last_up_to_date)
|
206
|
+
@last_up_to_date = last_up_to_date
|
207
|
+
end
|
208
|
+
|
209
|
+
# The Unix epoch millisecond timestamp of the last update to the {BigSegmentStore}. It is
|
210
|
+
# nil if the store has never been updated.
|
211
|
+
#
|
212
|
+
# @return [Integer|nil]
|
213
|
+
attr_reader :last_up_to_date
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Information about the status of a Big Segment store, provided by {BigSegmentStoreStatusProvider}.
|
218
|
+
#
|
219
|
+
# Big Segments are a specific type of segments. For more information, read the LaunchDarkly
|
220
|
+
# documentation: https://docs.launchdarkly.com/home/users/big-segments
|
221
|
+
#
|
222
|
+
class BigSegmentStoreStatus
|
223
|
+
def initialize(available, stale)
|
224
|
+
@available = available
|
225
|
+
@stale = stale
|
226
|
+
end
|
227
|
+
|
228
|
+
# True if the Big Segment store is able to respond to queries, so that the SDK can evaluate
|
229
|
+
# whether a context is in a segment or not.
|
230
|
+
#
|
231
|
+
# If this property is false, the store is not able to make queries (for instance, it may not have
|
232
|
+
# a valid database connection). In this case, the SDK will treat any reference to a Big Segment
|
233
|
+
# as if no contexts are included in that segment. Also, the {EvaluationReason} associated with
|
234
|
+
# with any flag evaluation that references a Big Segment when the store is not available will
|
235
|
+
# have a `big_segments_status` of `STORE_ERROR`.
|
236
|
+
#
|
237
|
+
# @return [Boolean]
|
238
|
+
attr_reader :available
|
239
|
+
|
240
|
+
# True if the Big Segment store is available, but has not been updated within the amount of time
|
241
|
+
# specified by {BigSegmentsConfig#stale_after}.
|
242
|
+
#
|
243
|
+
# This may indicate that the LaunchDarkly Relay Proxy, which populates the store, has stopped
|
244
|
+
# running or has become unable to receive fresh data from LaunchDarkly. Any feature flag
|
245
|
+
# evaluations that reference a Big Segment will be using the last known data, which may be out
|
246
|
+
# of date. Also, the {EvaluationReason} associated with those evaluations will have a
|
247
|
+
# `big_segments_status` of `STALE`.
|
248
|
+
#
|
249
|
+
# @return [Boolean]
|
250
|
+
attr_reader :stale
|
251
|
+
|
252
|
+
def ==(other)
|
253
|
+
self.available == other.available && self.stale == other.stale
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
# An interface for querying the status of a Big Segment store.
|
259
|
+
#
|
260
|
+
# The Big Segment store is the component that receives information about Big Segments, normally
|
261
|
+
# from a database populated by the LaunchDarkly Relay Proxy. Big Segments are a specific type
|
262
|
+
# of segments. For more information, read the LaunchDarkly documentation:
|
263
|
+
# https://docs.launchdarkly.com/home/users/big-segments
|
264
|
+
#
|
265
|
+
# An implementation of this interface is returned by {LDClient#big_segment_store_status_provider}.
|
266
|
+
# Application code never needs to implement this interface.
|
267
|
+
#
|
268
|
+
# There are two ways to interact with the status. One is to simply get the current status; if its
|
269
|
+
# `available` property is true, then the SDK is able to evaluate context membership in Big Segments,
|
270
|
+
# and the `stale`` property indicates whether the data might be out of date.
|
271
|
+
#
|
272
|
+
# The other way is to subscribe to status change notifications. Applications may wish to know if
|
273
|
+
# there is an outage in the Big Segment store, or if it has become stale (the Relay Proxy has
|
274
|
+
# stopped updating it with new data), since then flag evaluations that reference a Big Segment
|
275
|
+
# might return incorrect values. To allow finding out about status changes as soon as possible,
|
276
|
+
# `BigSegmentStoreStatusProvider` mixes in Ruby's
|
277
|
+
# [Observable](https://docs.ruby-lang.org/en/2.5.0/Observable.html) module to provide standard
|
278
|
+
# methods such as `add_observer`. Observers will be called with a new {BigSegmentStoreStatus}
|
279
|
+
# value whenever the status changes.
|
280
|
+
#
|
281
|
+
# @example Getting the current status
|
282
|
+
# status = client.big_segment_store_status_provider.status
|
283
|
+
#
|
284
|
+
# @example Subscribing to status notifications
|
285
|
+
# client.big_segment_store_status_provider.add_observer(self, :big_segments_status_changed)
|
286
|
+
#
|
287
|
+
# def big_segments_status_changed(new_status)
|
288
|
+
# puts "Big segment store status is now: #{new_status}"
|
289
|
+
# end
|
290
|
+
#
|
291
|
+
module BigSegmentStoreStatusProvider
|
292
|
+
include Observable
|
293
|
+
#
|
294
|
+
# Gets the current status of the store, if known.
|
295
|
+
#
|
296
|
+
# @return [BigSegmentStoreStatus] the status, or nil if the SDK has not yet queried the Big
|
297
|
+
# Segment store status
|
298
|
+
#
|
299
|
+
def status
|
300
|
+
end
|
301
|
+
end
|
152
302
|
end
|
153
303
|
end
|