launchdarkly-server-sdk 8.11.1 → 8.11.3

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +66 -3
  3. data/lib/ldclient-rb/context.rb +1 -1
  4. data/lib/ldclient-rb/data_system.rb +243 -0
  5. data/lib/ldclient-rb/events.rb +35 -20
  6. data/lib/ldclient-rb/flags_state.rb +1 -1
  7. data/lib/ldclient-rb/impl/big_segments.rb +4 -4
  8. data/lib/ldclient-rb/impl/cache_store.rb +44 -0
  9. data/lib/ldclient-rb/impl/data_source/null_processor.rb +52 -0
  10. data/lib/ldclient-rb/impl/data_source/polling.rb +108 -0
  11. data/lib/ldclient-rb/impl/data_source/requestor.rb +106 -0
  12. data/lib/ldclient-rb/impl/data_source/status_provider.rb +78 -0
  13. data/lib/ldclient-rb/impl/data_source/stream.rb +198 -0
  14. data/lib/ldclient-rb/impl/data_source.rb +3 -3
  15. data/lib/ldclient-rb/impl/data_store/data_kind.rb +108 -0
  16. data/lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb +187 -0
  17. data/lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb +130 -0
  18. data/lib/ldclient-rb/impl/data_store/status_provider.rb +82 -0
  19. data/lib/ldclient-rb/impl/data_store/store.rb +371 -0
  20. data/lib/ldclient-rb/impl/data_store.rb +11 -97
  21. data/lib/ldclient-rb/impl/data_system/fdv1.rb +178 -0
  22. data/lib/ldclient-rb/impl/data_system/fdv2.rb +471 -0
  23. data/lib/ldclient-rb/impl/data_system/polling.rb +601 -0
  24. data/lib/ldclient-rb/impl/data_system/protocolv2.rb +264 -0
  25. data/lib/ldclient-rb/impl/data_system.rb +298 -0
  26. data/lib/ldclient-rb/impl/dependency_tracker.rb +21 -9
  27. data/lib/ldclient-rb/impl/evaluator.rb +3 -2
  28. data/lib/ldclient-rb/impl/event_sender.rb +4 -3
  29. data/lib/ldclient-rb/impl/expiring_cache.rb +79 -0
  30. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +9 -9
  31. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source.rb +0 -1
  32. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb +288 -0
  33. data/lib/ldclient-rb/impl/memoized_value.rb +34 -0
  34. data/lib/ldclient-rb/impl/migrations/migrator.rb +2 -1
  35. data/lib/ldclient-rb/impl/migrations/tracker.rb +2 -1
  36. data/lib/ldclient-rb/impl/model/serialization.rb +6 -6
  37. data/lib/ldclient-rb/impl/non_blocking_thread_pool.rb +48 -0
  38. data/lib/ldclient-rb/impl/repeating_task.rb +2 -2
  39. data/lib/ldclient-rb/impl/simple_lru_cache.rb +27 -0
  40. data/lib/ldclient-rb/impl/util.rb +65 -0
  41. data/lib/ldclient-rb/impl.rb +1 -2
  42. data/lib/ldclient-rb/in_memory_store.rb +1 -18
  43. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +9 -9
  44. data/lib/ldclient-rb/integrations/test_data.rb +11 -11
  45. data/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +582 -0
  46. data/lib/ldclient-rb/integrations/test_data_v2.rb +248 -0
  47. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +3 -2
  48. data/lib/ldclient-rb/interfaces/data_system.rb +755 -0
  49. data/lib/ldclient-rb/interfaces/feature_store.rb +3 -0
  50. data/lib/ldclient-rb/ldclient.rb +55 -149
  51. data/lib/ldclient-rb/util.rb +11 -70
  52. data/lib/ldclient-rb/version.rb +1 -1
  53. data/lib/ldclient-rb.rb +8 -17
  54. metadata +52 -17
  55. data/lib/ldclient-rb/cache_store.rb +0 -45
  56. data/lib/ldclient-rb/expiring_cache.rb +0 -77
  57. data/lib/ldclient-rb/memoized_value.rb +0 -32
  58. data/lib/ldclient-rb/non_blocking_thread_pool.rb +0 -46
  59. data/lib/ldclient-rb/polling.rb +0 -102
  60. data/lib/ldclient-rb/requestor.rb +0 -102
  61. data/lib/ldclient-rb/simple_lru_cache.rb +0 -25
  62. data/lib/ldclient-rb/stream.rb +0 -196
@@ -103,6 +103,9 @@ module LaunchDarkly
103
103
  #
104
104
  # Performs any necessary cleanup to shut down the store when the client is being shut down.
105
105
  #
106
+ # This method should be idempotent - it is safe to call it multiple times, and subsequent
107
+ # calls after the first should have no effect.
108
+ #
106
109
  # @return [void]
107
110
  #
108
111
  def stop
@@ -1,13 +1,16 @@
1
1
  require "ldclient-rb/impl/big_segments"
2
2
  require "ldclient-rb/impl/broadcaster"
3
+ require "ldclient-rb/impl/context"
3
4
  require "ldclient-rb/impl/data_source"
4
5
  require "ldclient-rb/impl/data_store"
6
+ require "ldclient-rb/impl/data_system/fdv1"
5
7
  require "ldclient-rb/impl/diagnostic_events"
6
- require "ldclient-rb/impl/evaluator"
7
8
  require "ldclient-rb/impl/evaluation_with_hook_result"
9
+ require "ldclient-rb/impl/evaluator"
8
10
  require "ldclient-rb/impl/flag_tracker"
9
- require "ldclient-rb/impl/store_client_wrapper"
10
11
  require "ldclient-rb/impl/migrations/tracker"
12
+ require "ldclient-rb/impl/util"
13
+ require "ldclient-rb/events"
11
14
  require "concurrent"
12
15
  require "concurrent/atomics"
13
16
  require "digest/sha1"
@@ -29,6 +32,18 @@ module LaunchDarkly
29
32
 
30
33
  def_delegators :@config, :logger
31
34
 
35
+ # @!method flush
36
+ # Delegates to {LaunchDarkly::EventProcessorMethods#flush}.
37
+ def_delegator :@event_processor, :flush
38
+
39
+ # @!method data_store_status_provider
40
+ # Delegates to the data system {LaunchDarkly::Impl::DataSystem#data_store_status_provider}.
41
+ # @return [LaunchDarkly::Interfaces::DataStore::StatusProvider]
42
+ # @!method data_source_status_provider
43
+ # Delegates to the data system {LaunchDarkly::Impl::DataSystem#data_source_status_provider}.
44
+ # @return [LaunchDarkly::Interfaces::DataSource::StatusProvider]
45
+ def_delegators :@data_system, :data_store_status_provider, :data_source_status_provider
46
+
32
47
  #
33
48
  # Creates a new client instance that connects to LaunchDarkly. A custom
34
49
  # configuration parameter can also supplied to specify advanced options,
@@ -47,13 +62,16 @@ module LaunchDarkly
47
62
  #
48
63
  def initialize(sdk_key, config = Config.default, wait_for_sec = 5)
49
64
  # Note that sdk_key is normally a required parameter, and a nil value would cause the SDK to
50
- # fail in most configurations. However, there are some configurations where it would be OK
51
- # (offline = true, *or* we are using LDD mode or the file data source and events are disabled
52
- # so we're not connecting to any LD services) so rather than try to check for all of those
53
- # up front, we will let the constructors for the data source implementations implement this
54
- # fail-fast as appropriate, and just check here for the part regarding events.
55
- if !config.offline? && config.send_events
56
- raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil?
65
+ # fail in most configurations. However, there are some configurations where it would be OK to
66
+ # not provide a SDK key.
67
+ # * Offline mode
68
+ # * Using LDD mode with events disabled
69
+ # * Using a custom data source (like FileData) with events disabled
70
+ if !config.offline? && sdk_key.nil?
71
+ # If the data source is nil we create a default data source which requires the SDK key.
72
+ if config.send_events || (!config.use_ldd? && config.data_source.nil?)
73
+ raise ArgumentError, "sdk_key must not be nil"
74
+ end
57
75
  end
58
76
 
59
77
  @sdk_key = sdk_key
@@ -81,9 +99,10 @@ module LaunchDarkly
81
99
  # @param wait_for_sec [Float] maximum time (in seconds) to wait for initialization
82
100
  #
83
101
  def postfork(wait_for_sec = 5)
84
- @data_source = nil
102
+ @data_system = nil
85
103
  @event_processor = nil
86
104
  @big_segment_store_manager = nil
105
+ @flag_tracker = nil
87
106
 
88
107
  start_up(wait_for_sec)
89
108
  end
@@ -94,32 +113,22 @@ module LaunchDarkly
94
113
 
95
114
  @hooks = Concurrent::Array.new(@config.hooks + plugin_hooks)
96
115
 
97
- @shared_executor = Concurrent::SingleThreadExecutor.new
98
-
99
- data_store_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @config.logger)
100
- store_sink = LaunchDarkly::Impl::DataStore::UpdateSink.new(data_store_broadcaster)
101
-
102
- # We need to wrap the feature store object with a FeatureStoreClientWrapper in order to add
103
- # some necessary logic around updates. Unfortunately, we have code elsewhere that accesses
104
- # the feature store through the Config object, so we need to make a new Config that uses
105
- # the wrapped store.
106
- @store = Impl::FeatureStoreClientWrapper.new(@config.feature_store, store_sink, @config.logger)
107
- updated_config = @config.clone
108
- updated_config.instance_variable_set(:@feature_store, @store)
109
- @config = updated_config
110
-
111
- @data_store_status_provider = LaunchDarkly::Impl::DataStore::StatusProvider.new(@store, store_sink)
116
+ # Initialize the data system (FDv1 for now, will support FDv2 in the future)
117
+ # Note: FDv1 will update @config.feature_store to use its wrapped store
118
+ @data_system = Impl::DataSystem::FDv1.new(@sdk_key, @config)
112
119
 
120
+ # Components not managed by data system
113
121
  @big_segment_store_manager = Impl::BigSegmentStoreManager.new(@config.big_segments, @config.logger)
114
122
  @big_segment_store_status_provider = @big_segment_store_manager.status_provider
115
123
 
116
- get_flag = lambda { |key| @store.get(FEATURES, key) }
117
- get_segment = lambda { |key| @store.get(SEGMENTS, key) }
124
+ get_flag = lambda { |key| @data_system.store.get(Impl::DataStore::FEATURES, key) }
125
+ get_segment = lambda { |key| @data_system.store.get(Impl::DataStore::SEGMENTS, key) }
118
126
  get_big_segments_membership = lambda { |key| @big_segment_store_manager.get_context_membership(key) }
119
127
  @evaluator = LaunchDarkly::Impl::Evaluator.new(get_flag, get_segment, get_big_segments_membership, @config.logger)
120
128
 
121
129
  if !@config.offline? && @config.send_events && !@config.diagnostic_opt_out?
122
130
  diagnostic_accumulator = Impl::DiagnosticAccumulator.new(Impl::DiagnosticAccumulator.create_diagnostic_id(@sdk_key))
131
+ @data_system.set_diagnostic_accumulator(diagnostic_accumulator)
123
132
  else
124
133
  diagnostic_accumulator = nil
125
134
  end
@@ -130,38 +139,14 @@ module LaunchDarkly
130
139
  @event_processor = EventProcessor.new(@sdk_key, @config, nil, diagnostic_accumulator)
131
140
  end
132
141
 
133
- if @config.use_ldd?
134
- @config.logger.info { "[LDClient] Started LaunchDarkly Client in LDD mode" }
135
- @data_source = NullUpdateProcessor.new
136
- return # requestor and update processor are not used in this mode
137
- end
138
-
139
- flag_tracker_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @config.logger)
140
- @flag_tracker = LaunchDarkly::Impl::FlagTracker.new(flag_tracker_broadcaster, lambda { |key, context| variation(key, context, nil) })
141
-
142
- data_source_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @config.logger)
143
-
144
- # Make the update sink available on the config so that our data source factory can access the sink with a shared executor.
145
- @config.data_source_update_sink = LaunchDarkly::Impl::DataSource::UpdateSink.new(@store, data_source_broadcaster, flag_tracker_broadcaster)
146
-
147
- @data_source_status_provider = LaunchDarkly::Impl::DataSource::StatusProvider.new(data_source_broadcaster, @config.data_source_update_sink)
148
-
149
- data_source_or_factory = @config.data_source || self.method(:create_default_data_source)
150
- if data_source_or_factory.respond_to? :call
151
- # Currently, data source factories take two parameters unless they need to be aware of diagnostic_accumulator, in
152
- # which case they take three parameters. This will be changed in the future to use a less awkware mechanism.
153
- if data_source_or_factory.arity == 3
154
- @data_source = data_source_or_factory.call(@sdk_key, @config, diagnostic_accumulator)
155
- else
156
- @data_source = data_source_or_factory.call(@sdk_key, @config)
157
- end
158
- else
159
- @data_source = data_source_or_factory
160
- end
142
+ # Create the flag tracker using the broadcaster from the data system
143
+ eval_fn = lambda { |key, context| variation(key, context, nil) }
144
+ @flag_tracker = Impl::FlagTracker.new(@data_system.flag_change_broadcaster, eval_fn)
161
145
 
162
146
  register_plugins(environment_metadata)
163
147
 
164
- ready = @data_source.start
148
+ # Start the data system
149
+ ready = @data_system.start
165
150
 
166
151
  return unless wait_for_sec > 0
167
152
 
@@ -172,7 +157,7 @@ module LaunchDarkly
172
157
  ok = ready.wait(wait_for_sec)
173
158
  if !ok
174
159
  @config.logger.error { "[LDClient] Timeout encountered waiting for LaunchDarkly client initialization" }
175
- elsif !@data_source.initialized?
160
+ elsif !initialized?
176
161
  @config.logger.error { "[LDClient] LaunchDarkly client initialization failed" }
177
162
  end
178
163
  end
@@ -235,22 +220,6 @@ module LaunchDarkly
235
220
  @hooks.push(hook)
236
221
  end
237
222
 
238
- #
239
- # Tells the client that all pending analytics events should be delivered as soon as possible.
240
- #
241
- # When the LaunchDarkly client generates analytics events (from {#variation}, {#variation_detail},
242
- # {#identify}, or {#track}), they are queued on a worker thread. The event thread normally
243
- # sends all queued events to LaunchDarkly at regular intervals, controlled by the
244
- # {Config#flush_interval} option. Calling `flush` triggers a send without waiting for the
245
- # next interval.
246
- #
247
- # Flushing is asynchronous, so this method will return before it is complete. However, if you
248
- # call {#close}, events are guaranteed to be sent before that method returns.
249
- #
250
- def flush
251
- @event_processor.flush
252
- end
253
-
254
223
  #
255
224
  # Creates a hash string that can be used by the JavaScript SDK to identify a context.
256
225
  # For more information, see [Secure mode](https://docs.launchdarkly.com/sdk/features/secure-mode#ruby).
@@ -287,7 +256,7 @@ module LaunchDarkly
287
256
  # @return [Boolean] true if the client has been initialized
288
257
  #
289
258
  def initialized?
290
- @config.offline? || @config.use_ldd? || @data_source.initialized?
259
+ @data_system.data_availability == @data_system.target_availability
291
260
  end
292
261
 
293
262
  #
@@ -593,7 +562,7 @@ module LaunchDarkly
593
562
  return FeatureFlagsState.new(false) if @config.offline?
594
563
 
595
564
  unless initialized?
596
- if @store.initialized?
565
+ if @data_system.store.initialized?
597
566
  @config.logger.warn { "Called all_flags_state before client initialization; using last known values from data store" }
598
567
  else
599
568
  @config.logger.warn { "Called all_flags_state before client initialization. Data store not available; returning empty state" }
@@ -608,9 +577,9 @@ module LaunchDarkly
608
577
  end
609
578
 
610
579
  begin
611
- features = @store.all(FEATURES)
580
+ features = @data_system.store.all(Impl::DataStore::FEATURES)
612
581
  rescue => exn
613
- Util.log_exception(@config.logger, "Unable to read flags for all_flags_state", exn)
582
+ Impl::Util.log_exception(@config.logger, "Unable to read flags for all_flags_state", exn)
614
583
  return FeatureFlagsState.new(false)
615
584
  end
616
585
 
@@ -627,7 +596,7 @@ module LaunchDarkly
627
596
  detail = eval_result.detail
628
597
  rescue => exn
629
598
  detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_EXCEPTION))
630
- Util.log_exception(@config.logger, "Error evaluating flag \"#{k}\" in all_flags_state", exn)
599
+ Impl::Util.log_exception(@config.logger, "Error evaluating flag \"#{k}\" in all_flags_state", exn)
631
600
  end
632
601
 
633
602
  requires_experiment_data = experiment?(f, detail.reason)
@@ -655,11 +624,9 @@ module LaunchDarkly
655
624
  # @return [void]
656
625
  def close
657
626
  @config.logger.info { "[LDClient] Closing LaunchDarkly client..." }
658
- @data_source.stop
627
+ @data_system.stop
659
628
  @event_processor.stop
660
629
  @big_segment_store_manager.stop
661
- @store.stop
662
- @shared_executor.shutdown
663
630
  end
664
631
 
665
632
  #
@@ -670,33 +637,6 @@ module LaunchDarkly
670
637
  #
671
638
  attr_reader :big_segment_store_status_provider
672
639
 
673
- #
674
- # Returns an interface for tracking the status of a persistent data store.
675
- #
676
- # The {LaunchDarkly::Interfaces::DataStore::StatusProvider} has methods for
677
- # checking whether the data store is (as far as the SDK knows) currently
678
- # operational, tracking changes in this status, and getting cache
679
- # statistics. These are only relevant for a persistent data store; if you
680
- # are using an in-memory data store, then this method will return a stub
681
- # object that provides no information.
682
- #
683
- # @return [LaunchDarkly::Interfaces::DataStore::StatusProvider]
684
- #
685
- attr_reader :data_store_status_provider
686
-
687
- #
688
- # Returns an interface for tracking the status of the data source.
689
- #
690
- # The data source is the mechanism that the SDK uses to get feature flag
691
- # configurations, such as a streaming connection (the default) or poll
692
- # requests. The {LaunchDarkly::Interfaces::DataSource::StatusProvider} has
693
- # methods for checking whether the data source is (as far as the SDK knows)
694
- # currently operational and tracking changes in this status.
695
- #
696
- # @return [LaunchDarkly::Interfaces::DataSource::StatusProvider]
697
- #
698
- attr_reader :data_source_status_provider
699
-
700
640
  #
701
641
  # Returns an interface for tracking changes in feature flag configurations.
702
642
  #
@@ -704,23 +644,8 @@ module LaunchDarkly
704
644
  # requesting notifications about feature flag changes using an event
705
645
  # listener model.
706
646
  #
707
- attr_reader :flag_tracker
708
-
709
- private
710
-
711
- def create_default_data_source(sdk_key, config, diagnostic_accumulator)
712
- if config.offline?
713
- return NullUpdateProcessor.new
714
- end
715
- raise ArgumentError, "sdk_key must not be nil" if sdk_key.nil? # see LDClient constructor comment on sdk_key
716
- if config.stream?
717
- StreamProcessor.new(sdk_key, config, diagnostic_accumulator)
718
- else
719
- config.logger.info { "Disabling streaming API" }
720
- config.logger.warn { "You should only disable the streaming API if instructed to do so by LaunchDarkly support" }
721
- requestor = Requestor.new(sdk_key, config)
722
- PollingProcessor.new(config, requestor)
723
- end
647
+ def flag_tracker
648
+ @flag_tracker
724
649
  end
725
650
 
726
651
  #
@@ -730,7 +655,7 @@ module LaunchDarkly
730
655
  #
731
656
  # @return [Array<EvaluationDetail, [LaunchDarkly::Impl::Model::FeatureFlag, nil], [String, nil]>]
732
657
  #
733
- def variation_with_flag(key, context, default)
658
+ private def variation_with_flag(key, context, default)
734
659
  evaluate_internal(key, context, default, false)
735
660
  end
736
661
 
@@ -742,7 +667,7 @@ module LaunchDarkly
742
667
  #
743
668
  # @return [Array<EvaluationDetail, [LaunchDarkly::Impl::Model::FeatureFlag, nil], [String, nil]>]
744
669
  #
745
- def evaluate_internal(key, context, default, with_reasons)
670
+ private def evaluate_internal(key, context, default, with_reasons)
746
671
  if @config.offline?
747
672
  return Evaluator.error_result(EvaluationReason::ERROR_CLIENT_NOT_READY, default), nil, nil
748
673
  end
@@ -760,7 +685,7 @@ module LaunchDarkly
760
685
  end
761
686
 
762
687
  unless initialized?
763
- if @store.initialized?
688
+ if @data_system.store.initialized?
764
689
  @config.logger.warn { "[LDClient] Client has not finished initializing; using last known values from feature store" }
765
690
  else
766
691
  @config.logger.error { "[LDClient] Client has not finished initializing; feature store unavailable, returning default value" }
@@ -771,7 +696,7 @@ module LaunchDarkly
771
696
  end
772
697
 
773
698
  begin
774
- feature = @store.get(FEATURES, key)
699
+ feature = @data_system.store.get(Impl::DataStore::FEATURES, key)
775
700
  rescue
776
701
  # Ignored
777
702
  end
@@ -797,7 +722,7 @@ module LaunchDarkly
797
722
  record_flag_eval(feature, context, detail, default, with_reasons)
798
723
  [detail, feature, nil]
799
724
  rescue => exn
800
- Util.log_exception(@config.logger, "Error evaluating feature flag \"#{key}\"", exn)
725
+ Impl::Util.log_exception(@config.logger, "Error evaluating feature flag \"#{key}\"", exn)
801
726
  detail = Evaluator.error_result(EvaluationReason::ERROR_EXCEPTION, default)
802
727
  record_flag_eval_error(feature, context, default, detail.reason, with_reasons)
803
728
  [detail, feature, exn.to_s]
@@ -877,23 +802,4 @@ module LaunchDarkly
877
802
  false
878
803
  end
879
804
  end
880
-
881
- #
882
- # Used internally when the client is offline.
883
- # @private
884
- #
885
- class NullUpdateProcessor
886
- def start
887
- e = Concurrent::Event.new
888
- e.set
889
- e
890
- end
891
-
892
- def initialized?
893
- true
894
- end
895
-
896
- def stop
897
- end
898
- end
899
805
  end
@@ -1,5 +1,4 @@
1
- require "uri"
2
- require "http"
1
+ require "ldclient-rb/impl/util"
3
2
 
4
3
  module LaunchDarkly
5
4
  #
@@ -28,10 +27,11 @@ module LaunchDarkly
28
27
  #
29
28
  # @param error [String]
30
29
  # @param exception [Exception, nil]
30
+ # @param headers [Hash, nil]
31
31
  # @return [Result]
32
32
  #
33
- def self.fail(error, exception = nil)
34
- Result.new(nil, error, exception)
33
+ def self.fail(error, exception = nil, headers = nil)
34
+ Result.new(nil, error, exception, headers)
35
35
  end
36
36
 
37
37
  #
@@ -58,75 +58,16 @@ module LaunchDarkly
58
58
  #
59
59
  attr_reader :exception
60
60
 
61
- private def initialize(value, error = nil, exception = nil)
62
- @value = value
63
- @error = error
64
- @exception = exception
65
- end
66
- end
67
-
68
- # @private
69
- module Util
70
- #
71
- # Append the payload filter key query parameter to the provided URI.
72
61
  #
73
- # @param uri [String]
74
- # @param config [Config]
75
- # @return [String]
62
+ # @return [Hash] Optional headers associated with the result
76
63
  #
77
- def self.add_payload_filter_key(uri, config)
78
- return uri if config.payload_filter_key.nil?
79
-
80
- begin
81
- parsed = URI.parse(uri)
82
- new_query_params = URI.decode_www_form(String(parsed.query)) << ["filter", config.payload_filter_key]
83
- parsed.query = URI.encode_www_form(new_query_params)
84
- parsed.to_s
85
- rescue URI::InvalidURIError
86
- config.logger.warn { "[LDClient] URI could not be parsed. No filtering will be applied." }
87
- uri
88
- end
89
- end
64
+ attr_reader :headers
90
65
 
91
- def self.new_http_client(uri_s, config)
92
- http_client_options = {}
93
- if config.socket_factory
94
- http_client_options["socket_class"] = config.socket_factory
95
- end
96
- proxy = URI.parse(uri_s).find_proxy
97
- unless proxy.nil?
98
- http_client_options["proxy"] = {
99
- proxy_address: proxy.host,
100
- proxy_port: proxy.port,
101
- proxy_username: proxy.user,
102
- proxy_password: proxy.password,
103
- }
104
- end
105
- HTTP::Client.new(http_client_options)
106
- .timeout({
107
- read: config.read_timeout,
108
- connect: config.connect_timeout,
109
- })
110
- .persistent(uri_s)
111
- end
112
-
113
- def self.log_exception(logger, message, exc)
114
- logger.error { "[LDClient] #{message}: #{exc.inspect}" }
115
- logger.debug { "[LDClient] Exception trace: #{exc.backtrace}" }
116
- end
117
-
118
- def self.http_error_recoverable?(status)
119
- if status >= 400 && status < 500
120
- status == 400 || status == 408 || status == 429
121
- else
122
- true
123
- end
124
- end
125
-
126
- def self.http_error_message(status, context, recoverable_message)
127
- desc = (status == 401 || status == 403) ? " (invalid SDK key)" : ""
128
- message = Util.http_error_recoverable?(status) ? recoverable_message : "giving up permanently"
129
- "HTTP error #{status}#{desc} for #{context} - #{message}"
66
+ private def initialize(value, error = nil, exception = nil, headers = nil)
67
+ @value = value
68
+ @error = error
69
+ @exception = exception
70
+ @headers = headers || {}
130
71
  end
131
72
  end
132
73
  end
@@ -1,3 +1,3 @@
1
1
  module LaunchDarkly
2
- VERSION = "8.11.1" # x-release-please-version
2
+ VERSION = "8.11.3" # x-release-please-version
3
3
  end
data/lib/ldclient-rb.rb CHANGED
@@ -5,23 +5,14 @@
5
5
  module LaunchDarkly
6
6
  end
7
7
 
8
- require "ldclient-rb/version"
9
- require "ldclient-rb/interfaces"
10
- require "ldclient-rb/util"
11
- require "ldclient-rb/flags_state"
12
- require "ldclient-rb/migrations"
13
- require "ldclient-rb/ldclient"
14
- require "ldclient-rb/cache_store"
15
- require "ldclient-rb/expiring_cache"
16
- require "ldclient-rb/memoized_value"
17
- require "ldclient-rb/in_memory_store"
8
+ # Public APIs - these define the main interfaces users interact with
18
9
  require "ldclient-rb/config"
19
10
  require "ldclient-rb/context"
20
- require "ldclient-rb/reference"
21
- require "ldclient-rb/stream"
22
- require "ldclient-rb/polling"
23
- require "ldclient-rb/simple_lru_cache"
24
- require "ldclient-rb/non_blocking_thread_pool"
25
- require "ldclient-rb/events"
26
- require "ldclient-rb/requestor"
11
+ require "ldclient-rb/flags_state"
27
12
  require "ldclient-rb/integrations"
13
+ require "ldclient-rb/interfaces"
14
+ require "ldclient-rb/ldclient"
15
+ require "ldclient-rb/migrations"
16
+ require "ldclient-rb/reference"
17
+ require "ldclient-rb/util"
18
+ require "ldclient-rb/version"