launchdarkly-server-sdk 6.3.0 → 8.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 +3 -4
- data/lib/ldclient-rb/config.rb +112 -62
- data/lib/ldclient-rb/context.rb +444 -0
- data/lib/ldclient-rb/evaluation_detail.rb +26 -22
- data/lib/ldclient-rb/events.rb +256 -146
- data/lib/ldclient-rb/flags_state.rb +26 -15
- data/lib/ldclient-rb/impl/big_segments.rb +18 -18
- data/lib/ldclient-rb/impl/broadcaster.rb +78 -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/data_source.rb +188 -0
- data/lib/ldclient-rb/impl/data_store.rb +59 -0
- data/lib/ldclient-rb/impl/dependency_tracker.rb +102 -0
- data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
- data/lib/ldclient-rb/impl/evaluator.rb +386 -142
- 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 +7 -6
- data/lib/ldclient-rb/impl/event_summarizer.rb +68 -0
- data/lib/ldclient-rb/impl/event_types.rb +136 -0
- data/lib/ldclient-rb/impl/flag_tracker.rb +58 -0
- data/lib/ldclient-rb/impl/integrations/consul_impl.rb +19 -7
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +38 -30
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +24 -11
- data/lib/ldclient-rb/impl/integrations/redis_impl.rb +109 -12
- data/lib/ldclient-rb/impl/migrations/migrator.rb +287 -0
- data/lib/ldclient-rb/impl/migrations/tracker.rb +136 -0
- data/lib/ldclient-rb/impl/model/clause.rb +45 -0
- data/lib/ldclient-rb/impl/model/feature_flag.rb +255 -0
- data/lib/ldclient-rb/impl/model/preprocessed_data.rb +64 -0
- data/lib/ldclient-rb/impl/model/segment.rb +132 -0
- data/lib/ldclient-rb/impl/model/serialization.rb +54 -44
- data/lib/ldclient-rb/impl/repeating_task.rb +3 -4
- data/lib/ldclient-rb/impl/sampler.rb +25 -0
- data/lib/ldclient-rb/impl/store_client_wrapper.rb +102 -8
- 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 +59 -1
- data/lib/ldclient-rb/in_memory_store.rb +9 -2
- data/lib/ldclient-rb/integrations/consul.rb +2 -2
- data/lib/ldclient-rb/integrations/dynamodb.rb +2 -2
- data/lib/ldclient-rb/integrations/file_data.rb +4 -4
- data/lib/ldclient-rb/integrations/redis.rb +5 -5
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +287 -62
- data/lib/ldclient-rb/integrations/test_data.rb +18 -14
- data/lib/ldclient-rb/integrations/util/store_wrapper.rb +20 -9
- data/lib/ldclient-rb/interfaces.rb +600 -14
- data/lib/ldclient-rb/ldclient.rb +314 -134
- data/lib/ldclient-rb/memoized_value.rb +1 -1
- data/lib/ldclient-rb/migrations.rb +230 -0
- data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
- data/lib/ldclient-rb/polling.rb +52 -6
- data/lib/ldclient-rb/reference.rb +274 -0
- data/lib/ldclient-rb/requestor.rb +9 -11
- data/lib/ldclient-rb/stream.rb +96 -34
- data/lib/ldclient-rb/util.rb +97 -14
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +3 -4
- metadata +65 -23
- data/lib/ldclient-rb/event_summarizer.rb +0 -55
- data/lib/ldclient-rb/file_data_source.rb +0 -23
- 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,59 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
require "ldclient-rb/interfaces"
|
3
|
+
|
4
|
+
module LaunchDarkly
|
5
|
+
module Impl
|
6
|
+
module DataStore
|
7
|
+
class StatusProvider
|
8
|
+
include LaunchDarkly::Interfaces::DataStore::StatusProvider
|
9
|
+
|
10
|
+
def initialize(store, update_sink)
|
11
|
+
# @type [LaunchDarkly::Impl::FeatureStoreClientWrapper]
|
12
|
+
@store = store
|
13
|
+
# @type [UpdateSink]
|
14
|
+
@update_sink = update_sink
|
15
|
+
end
|
16
|
+
|
17
|
+
def status
|
18
|
+
@update_sink.last_status.get
|
19
|
+
end
|
20
|
+
|
21
|
+
def monitoring_enabled?
|
22
|
+
@store.monitoring_enabled?
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_listener(listener)
|
26
|
+
@update_sink.broadcaster.add_listener(listener)
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_listener(listener)
|
30
|
+
@update_sink.broadcaster.remove_listener(listener)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class UpdateSink
|
35
|
+
include LaunchDarkly::Interfaces::DataStore::UpdateSink
|
36
|
+
|
37
|
+
# @return [LaunchDarkly::Impl::Broadcaster]
|
38
|
+
attr_reader :broadcaster
|
39
|
+
|
40
|
+
# @return [Concurrent::AtomicReference]
|
41
|
+
attr_reader :last_status
|
42
|
+
|
43
|
+
def initialize(broadcaster)
|
44
|
+
@broadcaster = broadcaster
|
45
|
+
@last_status = Concurrent::AtomicReference.new(
|
46
|
+
LaunchDarkly::Interfaces::DataStore::Status.new(true, false)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def update_status(status)
|
51
|
+
return if status.nil?
|
52
|
+
|
53
|
+
old_status = @last_status.get_and_set(status)
|
54
|
+
@broadcaster.broadcast(status) unless old_status == status
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module LaunchDarkly
|
2
|
+
module Impl
|
3
|
+
class DependencyTracker
|
4
|
+
def initialize
|
5
|
+
@from = {}
|
6
|
+
@to = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# Updates the dependency graph when an item has changed.
|
11
|
+
#
|
12
|
+
# @param from_kind [Object] the changed item's kind
|
13
|
+
# @param from_key [String] the changed item's key
|
14
|
+
# @param from_item [Object] the changed item
|
15
|
+
#
|
16
|
+
def update_dependencies_from(from_kind, from_key, from_item)
|
17
|
+
from_what = { kind: from_kind, key: from_key }
|
18
|
+
updated_dependencies = DependencyTracker.compute_dependencies_from(from_kind, from_item)
|
19
|
+
|
20
|
+
old_dependency_set = @from[from_what]
|
21
|
+
unless old_dependency_set.nil?
|
22
|
+
old_dependency_set.each do |kind_and_key|
|
23
|
+
deps_to_this_old_dep = @to[kind_and_key]
|
24
|
+
deps_to_this_old_dep&.delete(from_what)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@from[from_what] = updated_dependencies
|
29
|
+
updated_dependencies.each do |kind_and_key|
|
30
|
+
deps_to_this_new_dep = @to[kind_and_key]
|
31
|
+
if deps_to_this_new_dep.nil?
|
32
|
+
deps_to_this_new_dep = Set.new
|
33
|
+
@to[kind_and_key] = deps_to_this_new_dep
|
34
|
+
end
|
35
|
+
deps_to_this_new_dep.add(from_what)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.segment_keys_from_clauses(clauses)
|
40
|
+
clauses.flat_map do |clause|
|
41
|
+
if clause.op == :segmentMatch
|
42
|
+
clause.values.map { |value| {kind: LaunchDarkly::SEGMENTS, key: value }}
|
43
|
+
else
|
44
|
+
[]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# @param from_kind [String]
|
51
|
+
# @param from_item [LaunchDarkly::Impl::Model::FeatureFlag, LaunchDarkly::Impl::Model::Segment]
|
52
|
+
# @return [Set]
|
53
|
+
#
|
54
|
+
def self.compute_dependencies_from(from_kind, from_item)
|
55
|
+
return Set.new if from_item.nil?
|
56
|
+
|
57
|
+
if from_kind == LaunchDarkly::FEATURES
|
58
|
+
prereq_keys = from_item.prerequisites.map { |prereq| {kind: from_kind, key: prereq.key} }
|
59
|
+
segment_keys = from_item.rules.flat_map { |rule| DependencyTracker.segment_keys_from_clauses(rule.clauses) }
|
60
|
+
|
61
|
+
results = Set.new(prereq_keys)
|
62
|
+
results.merge(segment_keys)
|
63
|
+
elsif from_kind == LaunchDarkly::SEGMENTS
|
64
|
+
kind_and_keys = from_item.rules.flat_map do |rule|
|
65
|
+
DependencyTracker.segment_keys_from_clauses(rule.clauses)
|
66
|
+
end
|
67
|
+
Set.new(kind_and_keys)
|
68
|
+
else
|
69
|
+
Set.new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Clear any tracked dependencies and reset the tracking state to a clean slate.
|
75
|
+
#
|
76
|
+
def reset
|
77
|
+
@from.clear
|
78
|
+
@to.clear
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# Populates the given set with the union of the initial item and all items that directly or indirectly
|
83
|
+
# depend on it (based on the current state of the dependency graph).
|
84
|
+
#
|
85
|
+
# @param items_out [Set]
|
86
|
+
# @param initial_modified_item [Object]
|
87
|
+
#
|
88
|
+
def add_affected_items(items_out, initial_modified_item)
|
89
|
+
return if items_out.include? initial_modified_item
|
90
|
+
|
91
|
+
items_out.add(initial_modified_item)
|
92
|
+
affected_items = @to[initial_modified_item]
|
93
|
+
|
94
|
+
return if affected_items.nil?
|
95
|
+
|
96
|
+
affected_items.each do |affected_item|
|
97
|
+
add_affected_items(items_out, affected_item)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -9,7 +9,7 @@ module LaunchDarkly
|
|
9
9
|
def self.create_diagnostic_id(sdk_key)
|
10
10
|
{
|
11
11
|
diagnosticId: SecureRandom.uuid,
|
12
|
-
sdkKeySuffix: sdk_key[-6..-1] || sdk_key
|
12
|
+
sdkKeySuffix: sdk_key[-6..-1] || sdk_key,
|
13
13
|
}
|
14
14
|
end
|
15
15
|
|
@@ -25,16 +25,16 @@ module LaunchDarkly
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def create_init_event(config)
|
28
|
-
|
28
|
+
{
|
29
29
|
kind: 'diagnostic-init',
|
30
30
|
creationDate: Util.current_time_millis,
|
31
31
|
id: @id,
|
32
32
|
configuration: DiagnosticAccumulator.make_config_data(config),
|
33
33
|
sdk: DiagnosticAccumulator.make_sdk_data(config),
|
34
|
-
platform: DiagnosticAccumulator.make_platform_data
|
34
|
+
platform: DiagnosticAccumulator.make_platform_data,
|
35
35
|
}
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
def record_stream_init(timestamp, failed, duration_millis)
|
39
39
|
@lock.synchronize do
|
40
40
|
@stream_inits.push({ timestamp: timestamp, failed: failed, durationMillis: duration_millis })
|
@@ -57,7 +57,7 @@ module LaunchDarkly
|
|
57
57
|
droppedEvents: dropped_events,
|
58
58
|
deduplicatedUsers: deduplicated_users,
|
59
59
|
eventsInLastBatch: events_in_last_batch,
|
60
|
-
streamInits: previous_stream_inits
|
60
|
+
streamInits: previous_stream_inits,
|
61
61
|
}
|
62
62
|
@data_since_date = current_time
|
63
63
|
event
|
@@ -73,12 +73,11 @@ module LaunchDarkly
|
|
73
73
|
diagnosticRecordingIntervalMillis: self.seconds_to_millis(config.diagnostic_recording_interval),
|
74
74
|
eventsCapacity: config.capacity,
|
75
75
|
eventsFlushIntervalMillis: self.seconds_to_millis(config.flush_interval),
|
76
|
-
inlineUsersInEvents: config.inline_users_in_events,
|
77
76
|
pollingIntervalMillis: self.seconds_to_millis(config.poll_interval),
|
78
77
|
socketTimeoutMillis: self.seconds_to_millis(config.read_timeout),
|
79
78
|
streamingDisabled: !config.stream?,
|
80
|
-
userKeysCapacity: config.
|
81
|
-
userKeysFlushIntervalMillis: self.seconds_to_millis(config.
|
79
|
+
userKeysCapacity: config.context_keys_capacity,
|
80
|
+
userKeysFlushIntervalMillis: self.seconds_to_millis(config.context_keys_flush_interval),
|
82
81
|
usingProxy: ENV.has_key?('http_proxy') || ENV.has_key?('https_proxy') || ENV.has_key?('HTTP_PROXY') || ENV.has_key?('HTTPS_PROXY'),
|
83
82
|
usingRelayDaemon: config.use_ldd?,
|
84
83
|
}
|
@@ -88,7 +87,7 @@ module LaunchDarkly
|
|
88
87
|
def self.make_sdk_data(config)
|
89
88
|
ret = {
|
90
89
|
name: 'ruby-server-sdk',
|
91
|
-
version: LaunchDarkly::VERSION
|
90
|
+
version: LaunchDarkly::VERSION,
|
92
91
|
}
|
93
92
|
if config.wrapper_name
|
94
93
|
ret[:wrapperName] = config.wrapper_name
|
@@ -105,7 +104,7 @@ module LaunchDarkly
|
|
105
104
|
osName: self.normalize_os_name(conf['host_os']),
|
106
105
|
osVersion: 'unknown', # there seems to be no portable way to detect this in Ruby
|
107
106
|
rubyVersion: conf['ruby_version'],
|
108
|
-
rubyImplementation: Object.constants.include?(:RUBY_ENGINE) ? RUBY_ENGINE : 'unknown'
|
107
|
+
rubyImplementation: Object.constants.include?(:RUBY_ENGINE) ? RUBY_ENGINE : 'unknown',
|
109
108
|
}
|
110
109
|
end
|
111
110
|
|