launchdarkly-server-sdk 6.3.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -4
  3. data/lib/ldclient-rb/config.rb +112 -62
  4. data/lib/ldclient-rb/context.rb +444 -0
  5. data/lib/ldclient-rb/evaluation_detail.rb +26 -22
  6. data/lib/ldclient-rb/events.rb +256 -146
  7. data/lib/ldclient-rb/flags_state.rb +26 -15
  8. data/lib/ldclient-rb/impl/big_segments.rb +18 -18
  9. data/lib/ldclient-rb/impl/broadcaster.rb +78 -0
  10. data/lib/ldclient-rb/impl/context.rb +96 -0
  11. data/lib/ldclient-rb/impl/context_filter.rb +145 -0
  12. data/lib/ldclient-rb/impl/data_source.rb +188 -0
  13. data/lib/ldclient-rb/impl/data_store.rb +59 -0
  14. data/lib/ldclient-rb/impl/dependency_tracker.rb +102 -0
  15. data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
  16. data/lib/ldclient-rb/impl/evaluator.rb +386 -142
  17. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  18. data/lib/ldclient-rb/impl/evaluator_helpers.rb +50 -0
  19. data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
  20. data/lib/ldclient-rb/impl/event_sender.rb +7 -6
  21. data/lib/ldclient-rb/impl/event_summarizer.rb +68 -0
  22. data/lib/ldclient-rb/impl/event_types.rb +136 -0
  23. data/lib/ldclient-rb/impl/flag_tracker.rb +58 -0
  24. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +19 -7
  25. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +38 -30
  26. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +24 -11
  27. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +109 -12
  28. data/lib/ldclient-rb/impl/migrations/migrator.rb +287 -0
  29. data/lib/ldclient-rb/impl/migrations/tracker.rb +136 -0
  30. data/lib/ldclient-rb/impl/model/clause.rb +45 -0
  31. data/lib/ldclient-rb/impl/model/feature_flag.rb +255 -0
  32. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +64 -0
  33. data/lib/ldclient-rb/impl/model/segment.rb +132 -0
  34. data/lib/ldclient-rb/impl/model/serialization.rb +54 -44
  35. data/lib/ldclient-rb/impl/repeating_task.rb +3 -4
  36. data/lib/ldclient-rb/impl/sampler.rb +25 -0
  37. data/lib/ldclient-rb/impl/store_client_wrapper.rb +102 -8
  38. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
  39. data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
  40. data/lib/ldclient-rb/impl/util.rb +59 -1
  41. data/lib/ldclient-rb/in_memory_store.rb +9 -2
  42. data/lib/ldclient-rb/integrations/consul.rb +2 -2
  43. data/lib/ldclient-rb/integrations/dynamodb.rb +2 -2
  44. data/lib/ldclient-rb/integrations/file_data.rb +4 -4
  45. data/lib/ldclient-rb/integrations/redis.rb +5 -5
  46. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +287 -62
  47. data/lib/ldclient-rb/integrations/test_data.rb +18 -14
  48. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +20 -9
  49. data/lib/ldclient-rb/interfaces.rb +600 -14
  50. data/lib/ldclient-rb/ldclient.rb +314 -134
  51. data/lib/ldclient-rb/memoized_value.rb +1 -1
  52. data/lib/ldclient-rb/migrations.rb +230 -0
  53. data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
  54. data/lib/ldclient-rb/polling.rb +52 -6
  55. data/lib/ldclient-rb/reference.rb +274 -0
  56. data/lib/ldclient-rb/requestor.rb +9 -11
  57. data/lib/ldclient-rb/stream.rb +96 -34
  58. data/lib/ldclient-rb/util.rb +97 -14
  59. data/lib/ldclient-rb/version.rb +1 -1
  60. data/lib/ldclient-rb.rb +3 -4
  61. metadata +65 -23
  62. data/lib/ldclient-rb/event_summarizer.rb +0 -55
  63. data/lib/ldclient-rb/file_data_source.rb +0 -23
  64. data/lib/ldclient-rb/impl/event_factory.rb +0 -126
  65. data/lib/ldclient-rb/newrelic.rb +0 -17
  66. data/lib/ldclient-rb/redis_store.rb +0 -88
  67. 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
- return {
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.user_keys_capacity,
81
- userKeysFlushIntervalMillis: self.seconds_to_millis(config.user_keys_flush_interval),
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