launchdarkly-server-sdk 8.11.2-java → 8.12.0-java

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +69 -9
  3. data/lib/ldclient-rb/context.rb +1 -1
  4. data/lib/ldclient-rb/data_system.rb +227 -0
  5. data/lib/ldclient-rb/events.rb +34 -19
  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/polling.rb +108 -0
  10. data/lib/ldclient-rb/impl/data_source/requestor.rb +113 -0
  11. data/lib/ldclient-rb/impl/data_source/status_provider.rb +83 -0
  12. data/lib/ldclient-rb/impl/data_source/stream.rb +198 -0
  13. data/lib/ldclient-rb/impl/data_source.rb +3 -3
  14. data/lib/ldclient-rb/impl/data_store/data_kind.rb +108 -0
  15. data/lib/ldclient-rb/impl/data_store/feature_store_client_wrapper.rb +187 -0
  16. data/lib/ldclient-rb/impl/data_store/in_memory_feature_store.rb +130 -0
  17. data/lib/ldclient-rb/impl/data_store/status_provider.rb +76 -0
  18. data/lib/ldclient-rb/impl/data_store/store.rb +371 -0
  19. data/lib/ldclient-rb/impl/data_store.rb +11 -97
  20. data/lib/ldclient-rb/impl/data_system/data_source_builder_common.rb +77 -0
  21. data/lib/ldclient-rb/impl/data_system/fdv1.rb +20 -7
  22. data/lib/ldclient-rb/impl/data_system/fdv2.rb +472 -0
  23. data/lib/ldclient-rb/impl/data_system/http_config_options.rb +32 -0
  24. data/lib/ldclient-rb/impl/data_system/polling.rb +628 -0
  25. data/lib/ldclient-rb/impl/data_system/protocolv2.rb +264 -0
  26. data/lib/ldclient-rb/impl/data_system/streaming.rb +401 -0
  27. data/lib/ldclient-rb/impl/dependency_tracker.rb +21 -9
  28. data/lib/ldclient-rb/impl/evaluator.rb +3 -2
  29. data/lib/ldclient-rb/impl/event_sender.rb +14 -6
  30. data/lib/ldclient-rb/impl/expiring_cache.rb +79 -0
  31. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
  32. data/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb +460 -0
  33. data/lib/ldclient-rb/impl/integrations/test_data/test_data_source_v2.rb +290 -0
  34. data/lib/ldclient-rb/impl/memoized_value.rb +34 -0
  35. data/lib/ldclient-rb/impl/migrations/migrator.rb +2 -1
  36. data/lib/ldclient-rb/impl/migrations/tracker.rb +2 -1
  37. data/lib/ldclient-rb/impl/model/serialization.rb +6 -6
  38. data/lib/ldclient-rb/impl/non_blocking_thread_pool.rb +48 -0
  39. data/lib/ldclient-rb/impl/repeating_task.rb +2 -2
  40. data/lib/ldclient-rb/impl/simple_lru_cache.rb +27 -0
  41. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +1 -1
  42. data/lib/ldclient-rb/impl/util.rb +71 -0
  43. data/lib/ldclient-rb/impl.rb +1 -2
  44. data/lib/ldclient-rb/in_memory_store.rb +1 -18
  45. data/lib/ldclient-rb/integrations/file_data.rb +67 -0
  46. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +9 -9
  47. data/lib/ldclient-rb/integrations/test_data.rb +11 -11
  48. data/lib/ldclient-rb/integrations/test_data_v2/flag_builder_v2.rb +582 -0
  49. data/lib/ldclient-rb/integrations/test_data_v2.rb +254 -0
  50. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +3 -2
  51. data/lib/ldclient-rb/interfaces/data_system.rb +704 -0
  52. data/lib/ldclient-rb/interfaces/feature_store.rb +5 -2
  53. data/lib/ldclient-rb/ldclient.rb +66 -132
  54. data/lib/ldclient-rb/util.rb +11 -70
  55. data/lib/ldclient-rb/version.rb +1 -1
  56. data/lib/ldclient-rb.rb +9 -17
  57. metadata +41 -19
  58. data/lib/ldclient-rb/cache_store.rb +0 -45
  59. data/lib/ldclient-rb/expiring_cache.rb +0 -77
  60. data/lib/ldclient-rb/memoized_value.rb +0 -32
  61. data/lib/ldclient-rb/non_blocking_thread_pool.rb +0 -46
  62. data/lib/ldclient-rb/polling.rb +0 -102
  63. data/lib/ldclient-rb/requestor.rb +0 -102
  64. data/lib/ldclient-rb/simple_lru_cache.rb +0 -25
  65. data/lib/ldclient-rb/stream.rb +0 -197
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d9e66b4d568f476ab565dfb9332242aa2f4cdc8b1feb741460945e6d9eadcb7
4
- data.tar.gz: 6b2af234cec690fcf0ef3b8c82f1aa8f504f26472a24eb6798a41f37070b9121
3
+ metadata.gz: 1725cd5066df8e5072abb09c606e0bda2784fb2b16640cdf6b557a4119e2356c
4
+ data.tar.gz: efbba66e2391376fdd945a7e26bbb429e121a127b267b1f14d7685d7f2098a3f
5
5
  SHA512:
6
- metadata.gz: a2e8a497b962919601f25bcd1aa66b3e5eddfa827b48437d42061f61ef81a4db94fddfd47efab499c5994775505943edad61008a84abc797889b6f46ad6d2243
7
- data.tar.gz: 3af46adb331c7be348ae42efcc4e6a84704f25484f53a407d0f4e12ecc4cdaff110ad0a6a042cbff0ad1e69e09118de2bf3b3ecce5699aa42aa825e2b73fb2d0
6
+ metadata.gz: aecbdb3e07abe04e7993fd7967ee10376bbb9e19e70558858fd11b16ee5a5f56327005c1b76df628bf3a5d552b6462b3d2e57a1d8dee0477e18454a0d3e30a66
7
+ data.tar.gz: 56b6cfad3066a766c76fdf70ab3f204778bf208cfda316eed9ba8bbf5106c8ccceb7c3fa436d6af8045093b61d741791a087df78cca21d937c47bb2eb018cf14
@@ -1,4 +1,8 @@
1
1
  require "logger"
2
+ require "ldclient-rb/impl/cache_store"
3
+ require "ldclient-rb/impl/data_system/http_config_options"
4
+ require "ldclient-rb/impl/data_system/polling"
5
+ require "ldclient-rb/impl/data_system/streaming"
2
6
 
3
7
  module LaunchDarkly
4
8
  #
@@ -44,6 +48,7 @@ module LaunchDarkly
44
48
  # @option opts [Hash] :application See {#application}
45
49
  # @option opts [String] :payload_filter_key See {#payload_filter_key}
46
50
  # @option opts [Boolean] :omit_anonymous_contexts See {#omit_anonymous_contexts}
51
+ # @option opts [DataSystemConfig] :data_system_config See {#data_system_config}
47
52
  # @option hooks [Array<Interfaces::Hooks::Hook]
48
53
  # @option plugins [Array<Interfaces::Plugins::Plugin]
49
54
  #
@@ -82,6 +87,7 @@ module LaunchDarkly
82
87
  @hooks = (opts[:hooks] || []).keep_if { |hook| hook.is_a? Interfaces::Hooks::Hook }
83
88
  @plugins = (opts[:plugins] || []).keep_if { |plugin| plugin.is_a? Interfaces::Plugins::Plugin }
84
89
  @omit_anonymous_contexts = opts.has_key?(:omit_anonymous_contexts) && opts[:omit_anonymous_contexts]
90
+ @data_system_config = opts[:data_system_config]
85
91
  @data_source_update_sink = nil
86
92
  @instance_id = nil
87
93
  end
@@ -96,7 +102,7 @@ module LaunchDarkly
96
102
  # Custom data source implementations should integrate with this sink if
97
103
  # they want to provide support for data source status listeners.
98
104
  #
99
- # @private
105
+ # @api private
100
106
  #
101
107
  attr_accessor :data_source_update_sink
102
108
 
@@ -108,7 +114,7 @@ module LaunchDarkly
108
114
  # property is not supported; it is temporarily being exposed to maintain
109
115
  # backwards compatibility while the SDK structure is updated.
110
116
  #
111
- # @private
117
+ # @api private
112
118
  #
113
119
  attr_accessor :instance_id
114
120
 
@@ -430,6 +436,15 @@ module LaunchDarkly
430
436
  #
431
437
  attr_reader :omit_anonymous_contexts
432
438
 
439
+ #
440
+ # Configuration for the upcoming enhanced data system design. This is
441
+ # experimental and should not be set without direction from LaunchDarkly
442
+ # support.
443
+ #
444
+ # @return [DataSystemConfig, nil]
445
+ #
446
+ attr_reader :data_system_config
447
+
433
448
 
434
449
  #
435
450
  # The default LaunchDarkly client configuration. This configuration sets
@@ -453,7 +468,7 @@ module LaunchDarkly
453
468
  # @return [String] "https://sdk.launchdarkly.com"
454
469
  #
455
470
  def self.default_base_uri
456
- "https://sdk.launchdarkly.com"
471
+ Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_BASE_URI
457
472
  end
458
473
 
459
474
  #
@@ -461,7 +476,7 @@ module LaunchDarkly
461
476
  # @return [String] "https://stream.launchdarkly.com"
462
477
  #
463
478
  def self.default_stream_uri
464
- "https://stream.launchdarkly.com"
479
+ Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_BASE_URI
465
480
  end
466
481
 
467
482
  #
@@ -477,7 +492,7 @@ module LaunchDarkly
477
492
  # @return [Object] the Rails cache if in Rails, or a simple in-memory implementation otherwise
478
493
  #
479
494
  def self.default_cache_store
480
- defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : ThreadSafeMemoryStore.new
495
+ defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : Impl::ThreadSafeMemoryStore.new
481
496
  end
482
497
 
483
498
  #
@@ -493,7 +508,7 @@ module LaunchDarkly
493
508
  # @return [Float] 10
494
509
  #
495
510
  def self.default_read_timeout
496
- 10
511
+ Impl::DataSystem::HttpConfigOptions::DEFAULT_READ_TIMEOUT
497
512
  end
498
513
 
499
514
  #
@@ -501,7 +516,7 @@ module LaunchDarkly
501
516
  # @return [Float] 1
502
517
  #
503
518
  def self.default_initial_reconnect_delay
504
- 1
519
+ Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_INITIAL_RECONNECT_DELAY
505
520
  end
506
521
 
507
522
  #
@@ -509,7 +524,7 @@ module LaunchDarkly
509
524
  # @return [Float] 2
510
525
  #
511
526
  def self.default_connect_timeout
512
- 2
527
+ Impl::DataSystem::HttpConfigOptions::DEFAULT_CONNECT_TIMEOUT
513
528
  end
514
529
 
515
530
  #
@@ -563,7 +578,7 @@ module LaunchDarkly
563
578
  # @return [Float] 30
564
579
  #
565
580
  def self.default_poll_interval
566
- 30
581
+ Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_POLL_INTERVAL
567
582
  end
568
583
 
569
584
  #
@@ -678,4 +693,49 @@ module LaunchDarkly
678
693
  # @return [Float]
679
694
  attr_reader :stale_after
680
695
  end
696
+
697
+ #
698
+ # Configuration for LaunchDarkly's data acquisition strategy.
699
+ #
700
+ # This is not stable and is not subject to any backwards compatibility guarantees
701
+ # or semantic versioning. It is not suitable for production usage.
702
+ #
703
+ class DataSystemConfig
704
+ #
705
+ # @param initializers [Array<#build(String, Config)>, nil] The (optional) array of builders
706
+ # @param synchronizers [Array<#build(String, Config)>, nil] The (optional) array of synchronizer builders
707
+ # @param data_store_mode [Symbol] The (optional) data store mode
708
+ # @param data_store [LaunchDarkly::Interfaces::FeatureStore, nil] The (optional) data store
709
+ # @param fdv1_fallback_synchronizer [#build(String, Config), nil]
710
+ # The (optional) builder for FDv1-compatible fallback synchronizer
711
+ #
712
+ def initialize(initializers: nil, synchronizers: nil,
713
+ data_store_mode: LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY, data_store: nil, fdv1_fallback_synchronizer: nil)
714
+ @initializers = initializers
715
+ @synchronizers = synchronizers
716
+ @data_store_mode = data_store_mode
717
+ @data_store = data_store
718
+ @fdv1_fallback_synchronizer = fdv1_fallback_synchronizer
719
+ end
720
+
721
+ # The initializer builders for the data system. Each builder responds to build(sdk_key, config) and returns an Initializer.
722
+ # @return [Array<#build(String, Config)>, nil]
723
+ attr_reader :initializers
724
+
725
+ # The synchronizer builders for the data system. Each builder responds to build(sdk_key, config) and returns a Synchronizer.
726
+ # @return [Array<#build(String, Config)>, nil]
727
+ attr_reader :synchronizers
728
+
729
+ # The data store mode.
730
+ # @return [Symbol]
731
+ attr_reader :data_store_mode
732
+
733
+ # The data store.
734
+ # @return [LaunchDarkly::Interfaces::FeatureStore, nil]
735
+ attr_reader :data_store
736
+
737
+ # The FDv1-compatible fallback synchronizer builder. Responds to build(sdk_key, config) and returns a Synchronizer.
738
+ # @return [#build(String, Config), nil]
739
+ attr_reader :fdv1_fallback_synchronizer
740
+ end
681
741
  end
@@ -48,7 +48,7 @@ module LaunchDarkly
48
48
  attr_reader :error
49
49
 
50
50
  #
51
- # @private
51
+ # @api private
52
52
  # @param key [String, nil]
53
53
  # @param fully_qualified_key [String, nil]
54
54
  # @param kind [String, nil]
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ldclient-rb/interfaces/data_system'
4
+ require 'ldclient-rb/config'
5
+ require 'ldclient-rb/impl/data_system/polling'
6
+ require 'ldclient-rb/impl/data_system/streaming'
7
+
8
+ module LaunchDarkly
9
+ #
10
+ # Configuration for LaunchDarkly's data acquisition strategy.
11
+ #
12
+ # This module provides factory methods for creating data system configurations.
13
+ #
14
+ module DataSystem
15
+ #
16
+ # Builder for the data system configuration.
17
+ #
18
+ class ConfigBuilder
19
+ def initialize
20
+ @initializers = nil
21
+ @synchronizers = nil
22
+ @fdv1_fallback_synchronizer = nil
23
+ @data_store_mode = LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY
24
+ @data_store = nil
25
+ end
26
+
27
+ #
28
+ # Sets the initializers for the data system.
29
+ #
30
+ # @param initializers [Array<#build(String, Config)>]
31
+ # Array of builders that respond to build(sdk_key, config) and return an Initializer
32
+ # @return [ConfigBuilder] self for chaining
33
+ #
34
+ def initializers(initializers)
35
+ @initializers = initializers
36
+ self
37
+ end
38
+
39
+ #
40
+ # Sets the synchronizers for the data system.
41
+ #
42
+ # @param synchronizers [Array<#build(String, Config)>]
43
+ # Array of builders that respond to build(sdk_key, config) and return a Synchronizer
44
+ # @return [ConfigBuilder] self for chaining
45
+ #
46
+ def synchronizers(synchronizers)
47
+ @synchronizers = synchronizers
48
+ self
49
+ end
50
+
51
+ #
52
+ # Configures the SDK with a fallback synchronizer that is compatible with
53
+ # the Flag Delivery v1 API.
54
+ #
55
+ # @param fallback [#build(String, Config)] Builder that responds to build(sdk_key, config) and returns the fallback Synchronizer
56
+ # @return [ConfigBuilder] self for chaining
57
+ #
58
+ def fdv1_compatible_synchronizer(fallback)
59
+ @fdv1_fallback_synchronizer = fallback
60
+ self
61
+ end
62
+
63
+ #
64
+ # Sets the data store configuration for the data system.
65
+ #
66
+ # @param data_store [LaunchDarkly::Interfaces::FeatureStore] The data store
67
+ # @param store_mode [Symbol] The store mode
68
+ # @return [ConfigBuilder] self for chaining
69
+ #
70
+ def data_store(data_store, store_mode)
71
+ @data_store = data_store
72
+ @data_store_mode = store_mode
73
+ self
74
+ end
75
+
76
+ #
77
+ # Builds the data system configuration.
78
+ #
79
+ # @return [DataSystemConfig]
80
+ #
81
+ def build
82
+ DataSystemConfig.new(
83
+ initializers: @initializers,
84
+ synchronizers: @synchronizers,
85
+ data_store_mode: @data_store_mode,
86
+ data_store: @data_store,
87
+ fdv1_fallback_synchronizer: @fdv1_fallback_synchronizer
88
+ )
89
+ end
90
+ end
91
+
92
+ #
93
+ # Returns a builder for creating a polling data source.
94
+ # This is a building block that can be used with {ConfigBuilder#initializers}
95
+ # or {ConfigBuilder#synchronizers} to create custom data system configurations.
96
+ #
97
+ # @return [LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder]
98
+ #
99
+ def self.polling_ds_builder
100
+ LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder.new
101
+ end
102
+
103
+ #
104
+ # Returns a builder for creating an FDv1 fallback polling data source.
105
+ # This is a building block that can be used with {ConfigBuilder#fdv1_compatible_synchronizer}
106
+ # to provide FDv1 compatibility in custom data system configurations.
107
+ #
108
+ # @return [LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder]
109
+ #
110
+ def self.fdv1_fallback_ds_builder
111
+ LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder.new
112
+ end
113
+
114
+ #
115
+ # Returns a builder for creating a streaming data source.
116
+ # This is a building block that can be used with {ConfigBuilder#synchronizers}
117
+ # to create custom data system configurations.
118
+ #
119
+ # @return [LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder]
120
+ #
121
+ def self.streaming_ds_builder
122
+ LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder.new
123
+ end
124
+
125
+ #
126
+ # Default is LaunchDarkly's recommended flag data acquisition strategy.
127
+ #
128
+ # Currently, it operates a two-phase method for obtaining data: first, it
129
+ # requests data from LaunchDarkly's global CDN. Then, it initiates a
130
+ # streaming connection to LaunchDarkly's Flag Delivery services to
131
+ # receive real-time updates.
132
+ #
133
+ # If the streaming connection is interrupted for an extended period of
134
+ # time, the SDK will automatically fall back to polling the global CDN
135
+ # for updates.
136
+ #
137
+ # @return [ConfigBuilder]
138
+ #
139
+ def self.default
140
+ polling_builder = polling_ds_builder
141
+ streaming_builder = streaming_ds_builder
142
+ fallback = fdv1_fallback_ds_builder
143
+
144
+ builder = ConfigBuilder.new
145
+ builder.initializers([polling_builder])
146
+ builder.synchronizers([streaming_builder, polling_builder])
147
+ builder.fdv1_compatible_synchronizer(fallback)
148
+
149
+ builder
150
+ end
151
+
152
+ #
153
+ # Streaming configures the SDK to efficiently stream flag/segment data
154
+ # in the background, allowing evaluations to operate on the latest data
155
+ # with no additional latency.
156
+ #
157
+ # @return [ConfigBuilder]
158
+ #
159
+ def self.streaming
160
+ streaming_builder = streaming_ds_builder
161
+ fallback = fdv1_fallback_ds_builder
162
+
163
+ builder = ConfigBuilder.new
164
+ builder.synchronizers([streaming_builder])
165
+ builder.fdv1_compatible_synchronizer(fallback)
166
+
167
+ builder
168
+ end
169
+
170
+ #
171
+ # Polling configures the SDK to regularly poll an endpoint for
172
+ # flag/segment data in the background. This is less efficient than
173
+ # streaming, but may be necessary in some network environments.
174
+ #
175
+ # @return [ConfigBuilder]
176
+ #
177
+ def self.polling
178
+ polling_builder = polling_ds_builder
179
+ fallback = fdv1_fallback_ds_builder
180
+
181
+ builder = ConfigBuilder.new
182
+ builder.synchronizers([polling_builder])
183
+ builder.fdv1_compatible_synchronizer(fallback)
184
+
185
+ builder
186
+ end
187
+
188
+ #
189
+ # Custom returns a builder suitable for creating a custom data
190
+ # acquisition strategy. You may configure how the SDK uses a Persistent
191
+ # Store, how the SDK obtains an initial set of data, and how the SDK
192
+ # keeps data up-to-date.
193
+ #
194
+ # @return [ConfigBuilder]
195
+ #
196
+ def self.custom
197
+ ConfigBuilder.new
198
+ end
199
+
200
+ #
201
+ # Daemon configures the SDK to read from a persistent store integration
202
+ # that is populated by Relay Proxy or other SDKs. The SDK will not connect
203
+ # to LaunchDarkly. In this mode, the SDK never writes to the data store.
204
+ #
205
+ # @param store [Object] The persistent store
206
+ # @return [ConfigBuilder]
207
+ #
208
+ def self.daemon(store)
209
+ custom.data_store(store, LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY)
210
+ end
211
+
212
+ #
213
+ # PersistentStore is similar to default, with the addition of a persistent
214
+ # store integration. Before data has arrived from LaunchDarkly, the SDK is
215
+ # able to evaluate flags using data from the persistent store. Once fresh
216
+ # data is available, the SDK will no longer read from the persistent store,
217
+ # although it will keep it up-to-date.
218
+ #
219
+ # @param store [Object] The persistent store
220
+ # @return [ConfigBuilder]
221
+ #
222
+ def self.persistent_store(store)
223
+ default.data_store(store, LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_WRITE)
224
+ end
225
+ end
226
+ end
227
+
@@ -3,6 +3,8 @@ require "ldclient-rb/impl/diagnostic_events"
3
3
  require "ldclient-rb/impl/event_sender"
4
4
  require "ldclient-rb/impl/event_summarizer"
5
5
  require "ldclient-rb/impl/event_types"
6
+ require "ldclient-rb/impl/non_blocking_thread_pool"
7
+ require "ldclient-rb/impl/simple_lru_cache"
6
8
  require "ldclient-rb/impl/util"
7
9
 
8
10
  require "concurrent"
@@ -60,6 +62,19 @@ module LaunchDarkly
60
62
  def record_migration_op_event(event)
61
63
  end
62
64
 
65
+ #
66
+ # Tells the event processor that all pending analytics events should be delivered as soon as possible.
67
+ #
68
+ # When the LaunchDarkly client generates analytics events (from {LaunchDarkly::LDClient#variation},
69
+ # {LaunchDarkly::LDClient#variation_detail}, {LaunchDarkly::LDClient#identify}, or
70
+ # {LaunchDarkly::LDClient#track}), they are queued on a worker thread. The event thread normally
71
+ # sends all queued events to LaunchDarkly at regular intervals, controlled by the
72
+ # {LaunchDarkly::Config#flush_interval} option. Calling `flush` triggers a send without waiting
73
+ # for the next interval.
74
+ #
75
+ # Flushing is asynchronous, so this method will return before it is complete. However, if you
76
+ # call {LaunchDarkly::LDClient#close}, events are guaranteed to be sent before that method returns.
77
+ #
63
78
  def flush
64
79
  end
65
80
 
@@ -70,24 +85,24 @@ module LaunchDarkly
70
85
  MAX_FLUSH_WORKERS = 5
71
86
  private_constant :MAX_FLUSH_WORKERS
72
87
 
73
- # @private
88
+ # @api private
74
89
  class NullEventProcessor
75
90
  include EventProcessorMethods
76
91
  end
77
92
 
78
- # @private
93
+ # @api private
79
94
  class FlushMessage
80
95
  end
81
96
 
82
- # @private
97
+ # @api private
83
98
  class FlushContextsMessage
84
99
  end
85
100
 
86
- # @private
101
+ # @api private
87
102
  class DiagnosticEventMessage
88
103
  end
89
104
 
90
- # @private
105
+ # @api private
91
106
  class SynchronousMessage
92
107
  def initialize
93
108
  @reply = Concurrent::Semaphore.new(0)
@@ -102,15 +117,15 @@ module LaunchDarkly
102
117
  end
103
118
  end
104
119
 
105
- # @private
120
+ # @api private
106
121
  class TestSyncMessage < SynchronousMessage
107
122
  end
108
123
 
109
- # @private
124
+ # @api private
110
125
  class StopMessage < SynchronousMessage
111
126
  end
112
127
 
113
- # @private
128
+ # @api private
114
129
  class EventProcessor
115
130
  include EventProcessorMethods
116
131
 
@@ -141,7 +156,7 @@ module LaunchDarkly
141
156
  @inbox_full = Concurrent::AtomicBoolean.new(false)
142
157
 
143
158
  event_sender = (test_properties || {})[:event_sender] ||
144
- Impl::EventSender.new(sdk_key, config, client || Util.new_http_client(config.events_uri, config))
159
+ Impl::EventSender.new(sdk_key, config)
145
160
 
146
161
  @timestamp_fn = (test_properties || {})[:timestamp_fn] || proc { Impl::Util.current_time_millis }
147
162
  @omit_anonymous_contexts = config.omit_anonymous_contexts
@@ -226,7 +241,7 @@ module LaunchDarkly
226
241
  end
227
242
  end
228
243
 
229
- # @private
244
+ # @api private
230
245
  class EventDispatcher
231
246
  def initialize(inbox, sdk_key, config, diagnostic_accumulator, event_sender)
232
247
  @sdk_key = sdk_key
@@ -235,7 +250,7 @@ module LaunchDarkly
235
250
  @event_sender = event_sender
236
251
  @sampler = LaunchDarkly::Impl::Sampler.new(Random.new)
237
252
 
238
- @context_keys = SimpleLRUCacheSet.new(config.context_keys_capacity)
253
+ @context_keys = Impl::SimpleLRUCacheSet.new(config.context_keys_capacity)
239
254
  @formatter = EventOutputFormatter.new(config)
240
255
  @disabled = Concurrent::AtomicBoolean.new(false)
241
256
  @last_known_past_time = Concurrent::AtomicReference.new(0)
@@ -243,10 +258,10 @@ module LaunchDarkly
243
258
  @events_in_last_batch = 0
244
259
 
245
260
  outbox = EventBuffer.new(config.capacity, config.logger)
246
- flush_workers = NonBlockingThreadPool.new(MAX_FLUSH_WORKERS, 'LD/EventDispatcher/FlushWorkers')
261
+ flush_workers = Impl::NonBlockingThreadPool.new(MAX_FLUSH_WORKERS, 'LD/EventDispatcher/FlushWorkers')
247
262
 
248
263
  if !@diagnostic_accumulator.nil?
249
- diagnostic_event_workers = NonBlockingThreadPool.new(1, 'LD/EventDispatcher/DiagnosticEventWorkers')
264
+ diagnostic_event_workers = Impl::NonBlockingThreadPool.new(1, 'LD/EventDispatcher/DiagnosticEventWorkers')
250
265
  init_event = @diagnostic_accumulator.create_init_event(config)
251
266
  send_diagnostic_event(init_event, diagnostic_event_workers)
252
267
  else
@@ -281,7 +296,7 @@ module LaunchDarkly
281
296
  dispatch_event(message, outbox)
282
297
  end
283
298
  rescue => e
284
- Util.log_exception(@config.logger, "Unexpected error in event processor", e)
299
+ Impl::Util.log_exception(@config.logger, "Unexpected error in event processor", e)
285
300
  end
286
301
  end
287
302
  end
@@ -383,7 +398,7 @@ module LaunchDarkly
383
398
  @last_known_past_time.value = (result.time_from_server.to_f * 1000).to_i
384
399
  end
385
400
  rescue => e
386
- Util.log_exception(@config.logger, "Unexpected error in event processor", e)
401
+ Impl::Util.log_exception(@config.logger, "Unexpected error in event processor", e)
387
402
  end
388
403
  end
389
404
  outbox.clear if success # Reset our internal state, these events now belong to the flush worker
@@ -408,16 +423,16 @@ module LaunchDarkly
408
423
  begin
409
424
  @event_sender.send_event_data(event.to_json, "diagnostic event", true)
410
425
  rescue => e
411
- Util.log_exception(@config.logger, "Unexpected error in event processor", e)
426
+ Impl::Util.log_exception(@config.logger, "Unexpected error in event processor", e)
412
427
  end
413
428
  end
414
429
  end
415
430
  end
416
431
 
417
- # @private
432
+ # @api private
418
433
  FlushPayload = Struct.new(:events, :summary)
419
434
 
420
- # @private
435
+ # @api private
421
436
  class EventBuffer
422
437
  def initialize(capacity, logger)
423
438
  @capacity = capacity
@@ -461,7 +476,7 @@ module LaunchDarkly
461
476
  end
462
477
  end
463
478
 
464
- # @private
479
+ # @api private
465
480
  class EventOutputFormatter
466
481
  FEATURE_KIND = 'feature'
467
482
  IDENTIFY_KIND = 'identify'
@@ -15,7 +15,7 @@ module LaunchDarkly
15
15
  end
16
16
 
17
17
  # Used internally to build the state map.
18
- # @private
18
+ # @api private
19
19
  def add_flag(flag_state, with_reasons, details_only_if_tracked)
20
20
  key = flag_state[:key]
21
21
  @flag_values[key] = flag_state[:value]
@@ -1,8 +1,8 @@
1
1
  require "ldclient-rb/config"
2
- require "ldclient-rb/expiring_cache"
2
+ require "ldclient-rb/impl/expiring_cache"
3
3
  require "ldclient-rb/impl/repeating_task"
4
+ require "ldclient-rb/impl/util"
4
5
  require "ldclient-rb/interfaces"
5
- require "ldclient-rb/util"
6
6
 
7
7
  require "digest"
8
8
 
@@ -45,7 +45,7 @@ module LaunchDarkly
45
45
  membership = EMPTY_MEMBERSHIP if membership.nil?
46
46
  @cache[context_key] = membership
47
47
  rescue => e
48
- LaunchDarkly::Util.log_exception(@logger, "Big Segment store membership query returned error", e)
48
+ Impl::Util.log_exception(@logger, "Big Segment store membership query returned error", e)
49
49
  return BigSegmentMembershipResult.new(nil, BigSegmentsStatus::STORE_ERROR)
50
50
  end
51
51
  end
@@ -67,7 +67,7 @@ module LaunchDarkly
67
67
  metadata = @store.get_metadata
68
68
  new_status = Interfaces::BigSegmentStoreStatus.new(true, !metadata || stale?(metadata.last_up_to_date))
69
69
  rescue => e
70
- LaunchDarkly::Util.log_exception(@logger, "Big Segment store status query returned error", e)
70
+ Impl::Util.log_exception(@logger, "Big Segment store status query returned error", e)
71
71
  end
72
72
  end
73
73
  @last_status = new_status
@@ -0,0 +1,44 @@
1
+ require "concurrent/map"
2
+
3
+ module LaunchDarkly
4
+ module Impl
5
+ # A thread-safe in-memory store that uses the same semantics that Faraday would expect, although we
6
+ # no longer use Faraday. This is used by Requestor, when we are not in a Rails environment.
7
+ class ThreadSafeMemoryStore
8
+ #
9
+ # Default constructor
10
+ #
11
+ # @return [ThreadSafeMemoryStore] a new store
12
+ def initialize
13
+ @cache = Concurrent::Map.new
14
+ end
15
+
16
+ #
17
+ # Read a value from the cache
18
+ # @param key [Object] the cache key
19
+ #
20
+ # @return [Object] the cache value
21
+ def read(key)
22
+ @cache[key]
23
+ end
24
+
25
+ #
26
+ # Store a value in the cache
27
+ # @param key [Object] the cache key
28
+ # @param value [Object] the value to associate with the key
29
+ #
30
+ # @return [Object] the value
31
+ def write(key, value)
32
+ @cache[key] = value
33
+ end
34
+
35
+ #
36
+ # Delete a value in the cache
37
+ # @param key [Object] the cache key
38
+ def delete(key)
39
+ @cache.delete(key)
40
+ end
41
+ end
42
+ end
43
+ end
44
+