launchdarkly-server-sdk 8.12.2 → 8.12.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ee161dc0454e83d98fd98b05e4853856cabd2478958ed90543c516968165fea
4
- data.tar.gz: 51086ed0c405546c21daf7c0df8bead73f57ab1951be7ba164f7fa4e50aad00a
3
+ metadata.gz: 57906761b3e8ac33ce67cb5fe508b930bced9dc76dc7627a11494ef30669cd31
4
+ data.tar.gz: 577eba2114e248f6c09e5d690d61a6213430c23a0edbef173c5ed60f4e3a0a58
5
5
  SHA512:
6
- metadata.gz: 2ae14ab7c225a213a1e1e0b9af55bc8a2c5afbc323b6689456f6eaaa6236bbb2ad9e390fcb4929ea4882c0156b1799bd3c52676d3ca092ba17ed39954862339a
7
- data.tar.gz: fdd3dd191f7c0ff949e4adef74aa484f89f7f15febb54eaa882f47c1301a833750f591686919c92410262c63440b98803f6c76112cced3a1035ccfa71e3c0705
6
+ metadata.gz: 3935eb8fbfee75a13469a4ebadf223654ac1116a8d5075948fa3f260ef35faaf0207c443b4af04f6ad1a71579db880790ea3506ec1c5591087e111c9b7659915
7
+ data.tar.gz: d3470ce5c0877f180aaafa35aa98cae50daef51148caeaaa8d61a9e3b3ca50770ec65a654d3fcc18f6069876eece3d51551b325ac988ba4c9fcc02f71ecc772b
@@ -468,7 +468,7 @@ module LaunchDarkly
468
468
  # @return [String] "https://sdk.launchdarkly.com"
469
469
  #
470
470
  def self.default_base_uri
471
- Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_BASE_URI
471
+ DataSystem::PollingDataSourceBuilder::DEFAULT_BASE_URI
472
472
  end
473
473
 
474
474
  #
@@ -476,7 +476,7 @@ module LaunchDarkly
476
476
  # @return [String] "https://stream.launchdarkly.com"
477
477
  #
478
478
  def self.default_stream_uri
479
- Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_BASE_URI
479
+ DataSystem::StreamingDataSourceBuilder::DEFAULT_BASE_URI
480
480
  end
481
481
 
482
482
  #
@@ -516,7 +516,7 @@ module LaunchDarkly
516
516
  # @return [Float] 1
517
517
  #
518
518
  def self.default_initial_reconnect_delay
519
- Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_INITIAL_RECONNECT_DELAY
519
+ DataSystem::StreamingDataSourceBuilder::DEFAULT_INITIAL_RECONNECT_DELAY
520
520
  end
521
521
 
522
522
  #
@@ -578,7 +578,7 @@ module LaunchDarkly
578
578
  # @return [Float] 30
579
579
  #
580
580
  def self.default_poll_interval
581
- Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_POLL_INTERVAL
581
+ DataSystem::PollingDataSourceBuilder::DEFAULT_POLL_INTERVAL
582
582
  end
583
583
 
584
584
  #
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ldclient-rb/interfaces/data_system"
4
+
5
+ module LaunchDarkly
6
+ module DataSystem
7
+ #
8
+ # Builder for the data system configuration.
9
+ #
10
+ # This builder configures the overall data acquisition strategy for the SDK,
11
+ # including which data sources to use for initialization and synchronization,
12
+ # and how to interact with a persistent data store.
13
+ #
14
+ # @see DataSystem.default
15
+ # @see DataSystem.streaming
16
+ # @see DataSystem.polling
17
+ # @see DataSystem.custom
18
+ #
19
+ class ConfigBuilder
20
+ def initialize
21
+ @initializers = nil
22
+ @synchronizers = nil
23
+ @fdv1_fallback_synchronizer = nil
24
+ @data_store_mode = LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY
25
+ @data_store = nil
26
+ end
27
+
28
+ #
29
+ # Sets the initializers for the data system.
30
+ #
31
+ # Initializers are used to fetch an initial set of data when the SDK starts.
32
+ # They are tried in order; if the first one fails, the next is tried, and so on.
33
+ #
34
+ # @param initializers [Array<#build(String, Config)>]
35
+ # Array of builders that respond to build(sdk_key, config) and return an Initializer
36
+ # @return [ConfigBuilder] self for chaining
37
+ #
38
+ def initializers(initializers)
39
+ @initializers = initializers
40
+ self
41
+ end
42
+
43
+ #
44
+ # Sets the synchronizers for the data system.
45
+ #
46
+ # Synchronizers keep data up-to-date after initialization. Like initializers,
47
+ # they are tried in order. If the primary synchronizer fails, the next one
48
+ # takes over.
49
+ #
50
+ # @param synchronizers [Array<#build(String, Config)>]
51
+ # Array of builders that respond to build(sdk_key, config) and return a Synchronizer
52
+ # @return [ConfigBuilder] self for chaining
53
+ #
54
+ def synchronizers(synchronizers)
55
+ @synchronizers = synchronizers
56
+ self
57
+ end
58
+
59
+ #
60
+ # Configures the SDK with a fallback synchronizer that is compatible with
61
+ # the Flag Delivery v1 API.
62
+ #
63
+ # This fallback is used when the server signals that the environment should
64
+ # revert to FDv1 protocol. Most users will not need to set this directly.
65
+ #
66
+ # @param fallback [#build(String, Config)] Builder that responds to build(sdk_key, config) and returns the fallback Synchronizer
67
+ # @return [ConfigBuilder] self for chaining
68
+ #
69
+ def fdv1_compatible_synchronizer(fallback)
70
+ @fdv1_fallback_synchronizer = fallback
71
+ self
72
+ end
73
+
74
+ #
75
+ # Sets the data store configuration for the data system.
76
+ #
77
+ # @param data_store [LaunchDarkly::Interfaces::FeatureStore] The data store
78
+ # @param store_mode [Symbol] The store mode (use constants from
79
+ # {LaunchDarkly::Interfaces::DataSystem::DataStoreMode})
80
+ # @return [ConfigBuilder] self for chaining
81
+ #
82
+ def data_store(data_store, store_mode)
83
+ @data_store = data_store
84
+ @data_store_mode = store_mode
85
+ self
86
+ end
87
+
88
+ #
89
+ # Builds the data system configuration.
90
+ #
91
+ # @return [DataSystemConfig]
92
+ #
93
+ def build
94
+ DataSystemConfig.new(
95
+ initializers: @initializers,
96
+ synchronizers: @synchronizers,
97
+ data_store_mode: @data_store_mode,
98
+ data_store: @data_store,
99
+ fdv1_fallback_synchronizer: @fdv1_fallback_synchronizer
100
+ )
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ldclient-rb/impl/data_system/http_config_options"
4
+
5
+ module LaunchDarkly
6
+ module DataSystem
7
+ #
8
+ # Common HTTP configuration methods shared by all data source builders.
9
+ #
10
+ # This module is included by {PollingDataSourceBuilder},
11
+ # {FDv1PollingDataSourceBuilder}, and {StreamingDataSourceBuilder} to provide
12
+ # a consistent set of HTTP connection settings.
13
+ #
14
+ # Each builder that includes this module must define a +DEFAULT_BASE_URI+ constant
15
+ # which is used as the fallback when {#base_uri} has not been called.
16
+ #
17
+ module DataSourceBuilderCommon
18
+ #
19
+ # Sets the base URI for HTTP requests.
20
+ #
21
+ # Use this to point the SDK at a Relay Proxy instance or any other URI
22
+ # that implements the corresponding LaunchDarkly API.
23
+ #
24
+ # @param uri [String] The base URI (e.g. "https://relay.example.com")
25
+ # @return [self] the builder, for chaining
26
+ #
27
+ def base_uri(uri)
28
+ @base_uri = uri
29
+ self
30
+ end
31
+
32
+ #
33
+ # Sets a custom socket factory for HTTP connections.
34
+ #
35
+ # @param factory [#open] A socket factory that responds to +open+
36
+ # @return [self] the builder, for chaining
37
+ #
38
+ def socket_factory(factory)
39
+ @socket_factory = factory
40
+ self
41
+ end
42
+
43
+ #
44
+ # Sets the read timeout for HTTP connections.
45
+ #
46
+ # @param timeout [Float] Timeout in seconds
47
+ # @return [self] the builder, for chaining
48
+ #
49
+ def read_timeout(timeout)
50
+ @read_timeout = timeout
51
+ self
52
+ end
53
+
54
+ #
55
+ # Sets the connect timeout for HTTP connections.
56
+ #
57
+ # @param timeout [Float] Timeout in seconds
58
+ # @return [self] the builder, for chaining
59
+ #
60
+ def connect_timeout(timeout)
61
+ @connect_timeout = timeout
62
+ self
63
+ end
64
+
65
+ #
66
+ # Builds an HttpConfigOptions instance from the current builder settings.
67
+ # Uses +self.class::DEFAULT_BASE_URI+ if {#base_uri} was not explicitly set.
68
+ # Read/connect timeouts default to HttpConfigOptions defaults if not set.
69
+ #
70
+ # @return [LaunchDarkly::Impl::DataSystem::HttpConfigOptions]
71
+ #
72
+ private def build_http_config
73
+ LaunchDarkly::Impl::DataSystem::HttpConfigOptions.new(
74
+ base_uri: (@base_uri || self.class::DEFAULT_BASE_URI).chomp("/"),
75
+ socket_factory: @socket_factory,
76
+ read_timeout: @read_timeout,
77
+ connect_timeout: @connect_timeout
78
+ )
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ldclient-rb/data_system/data_source_builder_common"
4
+
5
+ module LaunchDarkly
6
+ module DataSystem
7
+ #
8
+ # Interface for custom polling requesters.
9
+ #
10
+ # A Requester is responsible for fetching data from a data source. The SDK
11
+ # ships with built-in HTTP requesters for both FDv2 and FDv1 polling endpoints,
12
+ # but you can implement this interface to provide custom data fetching logic
13
+ # (e.g., reading from a file, a database, or a custom API).
14
+ #
15
+ # == Implementing a Custom Requester
16
+ #
17
+ # To create a custom requester, include this module and implement the {#fetch}
18
+ # method:
19
+ #
20
+ # class MyCustomRequester
21
+ # include LaunchDarkly::DataSystem::Requester
22
+ #
23
+ # def fetch(selector)
24
+ # # Fetch data and return a Result containing [ChangeSet, headers]
25
+ # # ...
26
+ # LaunchDarkly::Result.success([change_set, {}])
27
+ # end
28
+ #
29
+ # def stop
30
+ # # Clean up resources
31
+ # end
32
+ # end
33
+ #
34
+ # polling = LaunchDarkly::DataSystem.polling_ds_builder
35
+ # .requester(MyCustomRequester.new)
36
+ #
37
+ # @see PollingDataSourceBuilder#requester
38
+ #
39
+ module Requester
40
+ #
41
+ # Fetches data for the given selector.
42
+ #
43
+ # @param selector [LaunchDarkly::Interfaces::DataSystem::Selector, nil]
44
+ # The selector describing what data to fetch. May be nil if no
45
+ # selector is available (e.g., on the first request).
46
+ # @return [LaunchDarkly::Result] A Result containing a tuple of
47
+ # [ChangeSet, headers] on success, or an error message on failure.
48
+ #
49
+ def fetch(selector)
50
+ raise NotImplementedError
51
+ end
52
+
53
+ #
54
+ # Releases any resources held by this requester (e.g., persistent HTTP
55
+ # connections). Called when the requester is no longer needed.
56
+ #
57
+ # Implementations should handle being called multiple times gracefully.
58
+ # The default implementation is a no-op.
59
+ #
60
+ def stop
61
+ # Optional - implementations may override if they need cleanup
62
+ end
63
+ end
64
+
65
+ #
66
+ # Builder for a polling data source that communicates with LaunchDarkly's
67
+ # FDv2 polling endpoint.
68
+ #
69
+ # This builder can be used with {ConfigBuilder#initializers} or
70
+ # {ConfigBuilder#synchronizers} to create custom data system configurations.
71
+ #
72
+ # The polling data source periodically fetches data from LaunchDarkly. It
73
+ # supports conditional requests via ETags, so subsequent polls after the
74
+ # initial request only transfer data if changes have occurred.
75
+ #
76
+ # == Example
77
+ #
78
+ # polling = LaunchDarkly::DataSystem.polling_ds_builder
79
+ # .poll_interval(60)
80
+ # .base_uri("https://custom-endpoint.example.com")
81
+ #
82
+ # data_system = LaunchDarkly::DataSystem.custom
83
+ # .synchronizers([polling])
84
+ #
85
+ # @see DataSystem.polling_ds_builder
86
+ #
87
+ class PollingDataSourceBuilder
88
+ include LaunchDarkly::DataSystem::DataSourceBuilderCommon
89
+
90
+ # @return [String] The default base URI for polling requests
91
+ DEFAULT_BASE_URI = "https://sdk.launchdarkly.com"
92
+
93
+ # @return [Float] The default polling interval in seconds
94
+ DEFAULT_POLL_INTERVAL = 30
95
+
96
+ def initialize
97
+ @requester = nil
98
+ end
99
+
100
+ #
101
+ # Sets the polling interval in seconds.
102
+ #
103
+ # This controls how frequently the SDK polls LaunchDarkly for updates.
104
+ # Lower values mean more frequent updates but higher network traffic.
105
+ # The default is {DEFAULT_POLL_INTERVAL} seconds.
106
+ #
107
+ # @param secs [Float] Polling interval in seconds
108
+ # @return [PollingDataSourceBuilder] self for chaining
109
+ #
110
+ def poll_interval(secs)
111
+ @poll_interval = secs
112
+ self
113
+ end
114
+
115
+ #
116
+ # Sets a custom {Requester} for this polling data source.
117
+ #
118
+ # By default, the builder uses an HTTP requester that communicates with
119
+ # LaunchDarkly's FDv2 polling endpoint. Use this method to provide a
120
+ # custom requester implementation for testing or non-standard environments.
121
+ #
122
+ # @param requester [Requester] A custom requester that implements the
123
+ # {Requester} interface
124
+ # @return [PollingDataSourceBuilder] self for chaining
125
+ #
126
+ # @see Requester
127
+ #
128
+ def requester(requester)
129
+ @requester = requester
130
+ self
131
+ end
132
+
133
+ #
134
+ # Builds the polling data source with the configured parameters.
135
+ #
136
+ # This method is called internally by the SDK. You do not need to call it
137
+ # directly; instead, pass the builder to {ConfigBuilder#initializers} or
138
+ # {ConfigBuilder#synchronizers}.
139
+ #
140
+ # @param sdk_key [String] The SDK key
141
+ # @param config [LaunchDarkly::Config] The SDK configuration
142
+ # @return [LaunchDarkly::Impl::DataSystem::PollingDataSource]
143
+ #
144
+ def build(sdk_key, config)
145
+ http_opts = build_http_config
146
+ requester = @requester || LaunchDarkly::Impl::DataSystem::HTTPPollingRequester.new(sdk_key, http_opts, config)
147
+ LaunchDarkly::Impl::DataSystem::PollingDataSource.new(@poll_interval || DEFAULT_POLL_INTERVAL, requester, config.logger)
148
+ end
149
+ end
150
+
151
+ #
152
+ # Builder for a polling data source that communicates with LaunchDarkly's
153
+ # FDv1 (Flag Delivery v1) polling endpoint.
154
+ #
155
+ # This builder is typically used with {ConfigBuilder#fdv1_compatible_synchronizer}
156
+ # to provide a fallback when the server signals that the environment should
157
+ # revert to the FDv1 protocol.
158
+ #
159
+ # Most users will not need to interact with this builder directly, as the
160
+ # predefined strategies ({DataSystem.default}, {DataSystem.streaming},
161
+ # {DataSystem.polling}) already configure an appropriate FDv1 fallback.
162
+ #
163
+ # @see DataSystem.fdv1_fallback_ds_builder
164
+ #
165
+ class FDv1PollingDataSourceBuilder
166
+ include LaunchDarkly::DataSystem::DataSourceBuilderCommon
167
+
168
+ # @return [String] The default base URI for FDv1 polling requests
169
+ DEFAULT_BASE_URI = "https://sdk.launchdarkly.com"
170
+
171
+ # @return [Float] The default polling interval in seconds
172
+ DEFAULT_POLL_INTERVAL = 30
173
+
174
+ def initialize
175
+ @requester = nil
176
+ end
177
+
178
+ #
179
+ # Sets the polling interval in seconds.
180
+ #
181
+ # This controls how frequently the SDK polls LaunchDarkly for updates.
182
+ # The default is {DEFAULT_POLL_INTERVAL} seconds.
183
+ #
184
+ # @param secs [Float] Polling interval in seconds
185
+ # @return [FDv1PollingDataSourceBuilder] self for chaining
186
+ #
187
+ def poll_interval(secs)
188
+ @poll_interval = secs
189
+ self
190
+ end
191
+
192
+ #
193
+ # Sets a custom {Requester} for this polling data source.
194
+ #
195
+ # By default, the builder uses an HTTP requester that communicates with
196
+ # LaunchDarkly's FDv1 polling endpoint. Use this method to provide a
197
+ # custom requester implementation.
198
+ #
199
+ # @param requester [Requester] A custom requester that implements the
200
+ # {Requester} interface
201
+ # @return [FDv1PollingDataSourceBuilder] self for chaining
202
+ #
203
+ # @see Requester
204
+ #
205
+ def requester(requester)
206
+ @requester = requester
207
+ self
208
+ end
209
+
210
+ #
211
+ # Builds the FDv1 polling data source with the configured parameters.
212
+ #
213
+ # This method is called internally by the SDK. You do not need to call it
214
+ # directly; instead, pass the builder to {ConfigBuilder#fdv1_compatible_synchronizer}.
215
+ #
216
+ # @param sdk_key [String] The SDK key
217
+ # @param config [LaunchDarkly::Config] The SDK configuration
218
+ # @return [LaunchDarkly::Impl::DataSystem::PollingDataSource]
219
+ #
220
+ def build(sdk_key, config)
221
+ http_opts = build_http_config
222
+ requester = @requester || LaunchDarkly::Impl::DataSystem::HTTPFDv1PollingRequester.new(sdk_key, http_opts, config)
223
+ LaunchDarkly::Impl::DataSystem::PollingDataSource.new(@poll_interval || DEFAULT_POLL_INTERVAL, requester, config.logger)
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ldclient-rb/data_system/data_source_builder_common"
4
+
5
+ module LaunchDarkly
6
+ module DataSystem
7
+ #
8
+ # Builder for a streaming data source that uses Server-Sent Events (SSE)
9
+ # to receive real-time updates from LaunchDarkly's Flag Delivery services.
10
+ #
11
+ # This builder can be used with {ConfigBuilder#synchronizers} to create
12
+ # custom data system configurations. Streaming provides the lowest latency
13
+ # for flag updates compared to polling.
14
+ #
15
+ # == Example
16
+ #
17
+ # streaming = LaunchDarkly::DataSystem.streaming_ds_builder
18
+ # .initial_reconnect_delay(2)
19
+ # .base_uri("https://custom-stream.example.com")
20
+ #
21
+ # data_system = LaunchDarkly::DataSystem.custom
22
+ # .synchronizers([streaming])
23
+ #
24
+ # @see DataSystem.streaming_ds_builder
25
+ #
26
+ class StreamingDataSourceBuilder
27
+ include LaunchDarkly::DataSystem::DataSourceBuilderCommon
28
+
29
+ # @return [String] The default base URI for streaming connections
30
+ DEFAULT_BASE_URI = "https://stream.launchdarkly.com"
31
+
32
+ # @return [Float] The default initial reconnect delay in seconds
33
+ DEFAULT_INITIAL_RECONNECT_DELAY = 1
34
+
35
+ def initialize
36
+ # No initialization needed - defaults applied in build via nil-check
37
+ end
38
+
39
+ #
40
+ # Sets the initial delay before reconnecting after a stream connection error.
41
+ #
42
+ # The SDK uses an exponential backoff strategy starting from this delay.
43
+ # The default is {DEFAULT_INITIAL_RECONNECT_DELAY} second.
44
+ #
45
+ # @param delay [Float] Delay in seconds
46
+ # @return [StreamingDataSourceBuilder] self for chaining
47
+ #
48
+ def initial_reconnect_delay(delay)
49
+ @initial_reconnect_delay = delay
50
+ self
51
+ end
52
+
53
+ #
54
+ # Builds the streaming data source with the configured parameters.
55
+ #
56
+ # This method is called internally by the SDK. You do not need to call it
57
+ # directly; instead, pass the builder to {ConfigBuilder#synchronizers}.
58
+ #
59
+ # @param sdk_key [String] The SDK key
60
+ # @param config [LaunchDarkly::Config] The SDK configuration
61
+ # @return [LaunchDarkly::Impl::DataSystem::StreamingDataSource]
62
+ #
63
+ def build(sdk_key, config)
64
+ http_opts = build_http_config
65
+ LaunchDarkly::Impl::DataSystem::StreamingDataSource.new(
66
+ sdk_key, http_opts,
67
+ @initial_reconnect_delay || DEFAULT_INITIAL_RECONNECT_DELAY,
68
+ config
69
+ )
70
+ end
71
+ end
72
+ end
73
+ end
@@ -4,100 +4,66 @@ require 'ldclient-rb/interfaces/data_system'
4
4
  require 'ldclient-rb/config'
5
5
  require 'ldclient-rb/impl/data_system/polling'
6
6
  require 'ldclient-rb/impl/data_system/streaming'
7
+ require 'ldclient-rb/data_system/config_builder'
8
+ require 'ldclient-rb/data_system/polling_data_source_builder'
9
+ require 'ldclient-rb/data_system/streaming_data_source_builder'
7
10
 
8
11
  module LaunchDarkly
9
12
  #
10
13
  # Configuration for LaunchDarkly's data acquisition strategy.
11
14
  #
12
- # This module provides factory methods for creating data system configurations.
15
+ # This module provides factory methods for creating data system configurations,
16
+ # as well as builder classes for constructing individual data sources (polling
17
+ # and streaming).
18
+ #
19
+ # == Quick Start
20
+ #
21
+ # For most users, the predefined strategies are sufficient:
22
+ #
23
+ # # Use the default strategy (recommended)
24
+ # config = LaunchDarkly::Config.new(
25
+ # data_system: LaunchDarkly::DataSystem.default
26
+ # )
27
+ #
28
+ # # Use streaming only
29
+ # config = LaunchDarkly::Config.new(
30
+ # data_system: LaunchDarkly::DataSystem.streaming
31
+ # )
32
+ #
33
+ # # Use polling only
34
+ # config = LaunchDarkly::Config.new(
35
+ # data_system: LaunchDarkly::DataSystem.polling
36
+ # )
37
+ #
38
+ # == Custom Configurations
39
+ #
40
+ # For advanced use cases, you can build custom configurations using the
41
+ # data source builders:
42
+ #
43
+ # polling = LaunchDarkly::DataSystem.polling_ds_builder
44
+ # .poll_interval(60)
45
+ # .base_uri("https://custom-polling.example.com")
46
+ #
47
+ # streaming = LaunchDarkly::DataSystem.streaming_ds_builder
48
+ # .initial_reconnect_delay(2)
49
+ # .base_uri("https://custom-streaming.example.com")
50
+ #
51
+ # data_system = LaunchDarkly::DataSystem.custom
52
+ # .initializers([polling])
53
+ # .synchronizers([streaming, polling])
54
+ #
55
+ # config = LaunchDarkly::Config.new(data_system: data_system)
13
56
  #
14
57
  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
58
  #
93
59
  # Returns a builder for creating a polling data source.
94
60
  # This is a building block that can be used with {ConfigBuilder#initializers}
95
61
  # or {ConfigBuilder#synchronizers} to create custom data system configurations.
96
62
  #
97
- # @return [LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder]
63
+ # @return [PollingDataSourceBuilder]
98
64
  #
99
65
  def self.polling_ds_builder
100
- LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder.new
66
+ PollingDataSourceBuilder.new
101
67
  end
102
68
 
103
69
  #
@@ -105,10 +71,10 @@ module LaunchDarkly
105
71
  # This is a building block that can be used with {ConfigBuilder#fdv1_compatible_synchronizer}
106
72
  # to provide FDv1 compatibility in custom data system configurations.
107
73
  #
108
- # @return [LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder]
74
+ # @return [FDv1PollingDataSourceBuilder]
109
75
  #
110
76
  def self.fdv1_fallback_ds_builder
111
- LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder.new
77
+ FDv1PollingDataSourceBuilder.new
112
78
  end
113
79
 
114
80
  #
@@ -116,10 +82,10 @@ module LaunchDarkly
116
82
  # This is a building block that can be used with {ConfigBuilder#synchronizers}
117
83
  # to create custom data system configurations.
118
84
  #
119
- # @return [LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder]
85
+ # @return [StreamingDataSourceBuilder]
120
86
  #
121
87
  def self.streaming_ds_builder
122
- LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder.new
88
+ StreamingDataSourceBuilder.new
123
89
  end
124
90
 
125
91
  #
@@ -224,4 +190,3 @@ module LaunchDarkly
224
190
  end
225
191
  end
226
192
  end
227
-
@@ -178,7 +178,7 @@ module LaunchDarkly
178
178
  private def send_change_events(affected_items)
179
179
  affected_items.each do |item|
180
180
  if item[:kind] == Impl::DataStore::FEATURES
181
- @flag_change_broadcaster.broadcast(LaunchDarkly::Interfaces::FlagChange.new(item[:key]))
181
+ @flag_change_broadcaster.broadcast(LaunchDarkly::Interfaces::FlagChange.new(item[:key].to_s))
182
182
  end
183
183
  end
184
184
  end
@@ -58,7 +58,7 @@ module LaunchDarkly
58
58
  #
59
59
  # Initializes the store with a full set of data, replacing any existing data.
60
60
  #
61
- # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<String, Hash>>] Hash of data kinds to collections of items
61
+ # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<Symbol, Hash>>] Hash of data kinds to collections of items
62
62
  # @return [Boolean] true if successful, false otherwise
63
63
  #
64
64
  def set_basis(collections)
@@ -80,7 +80,7 @@ module LaunchDarkly
80
80
  #
81
81
  # Applies a delta update to the store.
82
82
  #
83
- # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<String, Hash>>] Hash of data kinds to collections with updates
83
+ # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<Symbol, Hash>>] Hash of data kinds to collections with updates
84
84
  # @return [Boolean] true if successful, false otherwise
85
85
  #
86
86
  def apply_delta(collections)
@@ -105,7 +105,7 @@ module LaunchDarkly
105
105
  #
106
106
  # Decodes a collection of items.
107
107
  #
108
- # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<String, Hash>>] Hash of data kinds to collections
108
+ # @param collections [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<Symbol, Hash>>] Hash of data kinds to collections
109
109
  # @return [Hash<LaunchDarkly::Impl::DataStore::DataKind, Hash<Symbol, Hash>>, nil] Decoded collection with symbol keys, or nil on error
110
110
  #
111
111
  private def decode_collection(collections)
@@ -193,7 +193,7 @@ module LaunchDarkly
193
193
  #
194
194
  # Set the basis of the store. Any existing data is discarded.
195
195
  #
196
- # @param collections [Hash{Object => Hash{String => Hash}}] Hash of data kinds to collections of items
196
+ # @param collections [Hash{Object => Hash{Symbol => Hash}}] Hash of data kinds to collections of items
197
197
  # @param selector [LaunchDarkly::Interfaces::DataSystem::Selector, nil] The selector
198
198
  # @param persist [Boolean] Whether to persist the data
199
199
  # @return [void]
@@ -234,7 +234,7 @@ module LaunchDarkly
234
234
  #
235
235
  # Apply a delta update to the store.
236
236
  #
237
- # @param collections [Hash{Object => Hash{String => Hash}}] Hash of data kinds to collections with updates
237
+ # @param collections [Hash{Object => Hash{Symbol => Hash}}] Hash of data kinds to collections with updates
238
238
  # @param selector [LaunchDarkly::Interfaces::DataSystem::Selector, nil] The selector
239
239
  # @param persist [Boolean] Whether to persist the changes
240
240
  # @return [void]
@@ -328,7 +328,7 @@ module LaunchDarkly
328
328
  private def send_change_events(affected_items)
329
329
  affected_items.each do |item|
330
330
  if item[:kind] == FEATURES
331
- @flag_change_broadcaster.broadcast(LaunchDarkly::Interfaces::FlagChange.new(item[:key]))
331
+ @flag_change_broadcaster.broadcast(LaunchDarkly::Interfaces::FlagChange.new(item[:key].to_s))
332
332
  end
333
333
  end
334
334
  end
@@ -336,8 +336,8 @@ module LaunchDarkly
336
336
  #
337
337
  # Compute which items changed between old and new data sets.
338
338
  #
339
- # @param old_data [Hash{DataKind => Hash{String => Hash}}] Old data hash
340
- # @param new_data [Hash{DataKind => Hash{String => Hash}}] New data hash
339
+ # @param old_data [Hash{DataKind => Hash{Symbol => Hash}}] Old data hash
340
+ # @param new_data [Hash{DataKind => Hash{Symbol => Hash}}] New data hash
341
341
  # @return [Set<Hash>] Set of {kind:, key:} hashes
342
342
  #
343
343
  private def compute_changed_items_for_full_data_set(old_data, new_data)
@@ -4,7 +4,7 @@ require "ldclient-rb/interfaces"
4
4
  require "ldclient-rb/interfaces/data_system"
5
5
  require "ldclient-rb/impl/data_system"
6
6
  require "ldclient-rb/impl/data_system/protocolv2"
7
- require "ldclient-rb/impl/data_system/data_source_builder_common"
7
+ require "ldclient-rb/data_system/polling_data_source_builder"
8
8
  require "ldclient-rb/impl/data_source/requestor"
9
9
  require "ldclient-rb/impl/util"
10
10
  require "concurrent"
@@ -21,32 +21,6 @@ module LaunchDarkly
21
21
  LD_ENVID_HEADER = "X-LD-EnvID"
22
22
  LD_FD_FALLBACK_HEADER = "X-LD-FD-Fallback"
23
23
 
24
- #
25
- # Requester protocol for polling data source
26
- #
27
- module Requester
28
- #
29
- # Fetches the data for the given selector.
30
- # Returns a Result containing a tuple of [ChangeSet, headers],
31
- # or an error if the data could not be retrieved.
32
- #
33
- # @param selector [LaunchDarkly::Interfaces::DataSystem::Selector, nil]
34
- # @return [Result]
35
- #
36
- def fetch(selector)
37
- raise NotImplementedError
38
- end
39
-
40
- #
41
- # Closes any persistent connections and releases resources.
42
- # This method should be called when the requester is no longer needed.
43
- # Implementations should handle being called multiple times gracefully.
44
- #
45
- def stop
46
- # Optional - implementations may override if they need cleanup
47
- end
48
- end
49
-
50
24
  #
51
25
  # PollingDataSource is a data source that can retrieve information from
52
26
  # LaunchDarkly either as an Initializer or as a Synchronizer.
@@ -246,7 +220,7 @@ module LaunchDarkly
246
220
  # requests to the FDv2 polling endpoint.
247
221
  #
248
222
  class HTTPPollingRequester
249
- include Requester
223
+ include LaunchDarkly::DataSystem::Requester
250
224
 
251
225
  #
252
226
  # @param sdk_key [String]
@@ -338,7 +312,7 @@ module LaunchDarkly
338
312
  # requests to the FDv1 polling endpoint.
339
313
  #
340
314
  class HTTPFDv1PollingRequester
341
- include Requester
315
+ include LaunchDarkly::DataSystem::Requester
342
316
 
343
317
  #
344
318
  # @param sdk_key [String]
@@ -526,103 +500,6 @@ module LaunchDarkly
526
500
  LaunchDarkly::Result.success(builder.finish(selector))
527
501
  end
528
502
 
529
- #
530
- # Builder for a PollingDataSource.
531
- #
532
- class PollingDataSourceBuilder
533
- include DataSourceBuilderCommon
534
-
535
- DEFAULT_BASE_URI = "https://sdk.launchdarkly.com"
536
- DEFAULT_POLL_INTERVAL = 30
537
-
538
- def initialize
539
- @requester = nil
540
- end
541
-
542
- #
543
- # Sets the polling interval in seconds.
544
- #
545
- # @param secs [Float] Polling interval in seconds
546
- # @return [PollingDataSourceBuilder]
547
- #
548
- def poll_interval(secs)
549
- @poll_interval = secs
550
- self
551
- end
552
-
553
- #
554
- # Sets a custom Requester for the PollingDataSource.
555
- #
556
- # @param requester [Requester]
557
- # @return [PollingDataSourceBuilder]
558
- #
559
- def requester(requester)
560
- @requester = requester
561
- self
562
- end
563
-
564
- #
565
- # Builds the PollingDataSource with the configured parameters.
566
- #
567
- # @param sdk_key [String]
568
- # @param config [LaunchDarkly::Config]
569
- # @return [PollingDataSource]
570
- #
571
- def build(sdk_key, config)
572
- http_opts = build_http_config
573
- requester = @requester || HTTPPollingRequester.new(sdk_key, http_opts, config)
574
- PollingDataSource.new(@poll_interval || DEFAULT_POLL_INTERVAL, requester, config.logger)
575
- end
576
- end
577
-
578
- #
579
- # Builder for an FDv1 PollingDataSource.
580
- #
581
- class FDv1PollingDataSourceBuilder
582
- include DataSourceBuilderCommon
583
-
584
- DEFAULT_BASE_URI = "https://sdk.launchdarkly.com"
585
- DEFAULT_POLL_INTERVAL = 30
586
-
587
- def initialize
588
- @requester = nil
589
- end
590
-
591
- #
592
- # Sets the polling interval in seconds.
593
- #
594
- # @param secs [Float] Polling interval in seconds
595
- # @return [FDv1PollingDataSourceBuilder]
596
- #
597
- def poll_interval(secs)
598
- @poll_interval = secs
599
- self
600
- end
601
-
602
- #
603
- # Sets a custom Requester for the PollingDataSource.
604
- #
605
- # @param requester [Requester]
606
- # @return [FDv1PollingDataSourceBuilder]
607
- #
608
- def requester(requester)
609
- @requester = requester
610
- self
611
- end
612
-
613
- #
614
- # Builds the PollingDataSource with the configured parameters.
615
- #
616
- # @param sdk_key [String]
617
- # @param config [LaunchDarkly::Config]
618
- # @return [PollingDataSource]
619
- #
620
- def build(sdk_key, config)
621
- http_opts = build_http_config
622
- requester = @requester || HTTPFDv1PollingRequester.new(sdk_key, http_opts, config)
623
- PollingDataSource.new(@poll_interval || DEFAULT_POLL_INTERVAL, requester, config.logger)
624
- end
625
- end
626
503
  end
627
504
  end
628
505
  end
@@ -5,7 +5,7 @@ require "ldclient-rb/interfaces/data_system"
5
5
  require "ldclient-rb/impl/data_system"
6
6
  require "ldclient-rb/impl/data_system/protocolv2"
7
7
  require "ldclient-rb/impl/data_system/polling" # For shared constants
8
- require "ldclient-rb/impl/data_system/data_source_builder_common"
8
+ require "ldclient-rb/data_system/streaming_data_source_builder"
9
9
  require "ldclient-rb/impl/util"
10
10
  require "concurrent"
11
11
  require "json"
@@ -356,46 +356,6 @@ module LaunchDarkly
356
356
  end
357
357
  end
358
358
 
359
- #
360
- # Builder for a StreamingDataSource.
361
- #
362
- class StreamingDataSourceBuilder
363
- include DataSourceBuilderCommon
364
-
365
- DEFAULT_BASE_URI = "https://stream.launchdarkly.com"
366
- DEFAULT_INITIAL_RECONNECT_DELAY = 1
367
-
368
- def initialize
369
- # No initialization needed - defaults applied in build via nil-check
370
- end
371
-
372
- #
373
- # Sets the initial delay before reconnecting after an error.
374
- #
375
- # @param delay [Float] Delay in seconds
376
- # @return [StreamingDataSourceBuilder]
377
- #
378
- def initial_reconnect_delay(delay)
379
- @initial_reconnect_delay = delay
380
- self
381
- end
382
-
383
- #
384
- # Builds the StreamingDataSource with the configured parameters.
385
- #
386
- # @param sdk_key [String]
387
- # @param config [LaunchDarkly::Config]
388
- # @return [StreamingDataSource]
389
- #
390
- def build(sdk_key, config)
391
- http_opts = build_http_config
392
- StreamingDataSource.new(
393
- sdk_key, http_opts,
394
- @initial_reconnect_delay || DEFAULT_INITIAL_RECONNECT_DELAY,
395
- config
396
- )
397
- end
398
- end
399
359
  end
400
360
  end
401
361
  end
@@ -13,7 +13,7 @@ module LaunchDarkly
13
13
  # Updates the dependency graph when an item has changed.
14
14
  #
15
15
  # @param from_kind [Object] the changed item's kind
16
- # @param from_key [String] the changed item's key
16
+ # @param from_key [Symbol] the changed item's key
17
17
  # @param from_item [Object] the changed item (can be a Hash, model object, or nil)
18
18
  #
19
19
  def update_dependencies_from(from_kind, from_key, from_item)
@@ -26,7 +26,7 @@ module LaunchDarkly
26
26
  # An adapter which turns a normal flag change listener into a flag value change listener.
27
27
  #
28
28
  class FlagValueChangeAdapter
29
- # @param [Symbol] flag_key
29
+ # @param [String] flag_key
30
30
  # @param [LaunchDarkly::LDContext] context
31
31
  # @param [#update] listener
32
32
  # @param [#call] eval_fn
@@ -66,7 +66,7 @@ module LaunchDarkly
66
66
  # The returned listener represents the subscription that was created by this method
67
67
  # call; to unsubscribe, pass that object (not your listener) to {#remove_listener}.
68
68
  #
69
- # @param key [Symbol]
69
+ # @param key [String]
70
70
  # @param context [LaunchDarkly::LDContext]
71
71
  # @param listener [#update]
72
72
  #
@@ -79,7 +79,7 @@ module LaunchDarkly
79
79
  class FlagChange
80
80
  attr_accessor :key
81
81
 
82
- # @param [Symbol] key
82
+ # @param key [String]
83
83
  def initialize(key)
84
84
  @key = key
85
85
  end
@@ -93,9 +93,9 @@ module LaunchDarkly
93
93
  attr_accessor :old_value
94
94
  attr_accessor :new_value
95
95
 
96
- # @param [Symbol] key
97
- # @param [Object] old_value
98
- # @param [Object] new_value
96
+ # @param key [String]
97
+ # @param old_value [Object]
98
+ # @param new_value [Object]
99
99
  def initialize(key, old_value, new_value)
100
100
  @key = key
101
101
  @old_value = old_value
@@ -1,3 +1,3 @@
1
1
  module LaunchDarkly
2
- VERSION = "8.12.2" # x-release-please-version
2
+ VERSION = "8.12.3" # x-release-please-version
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: launchdarkly-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.12.2
4
+ version: 8.12.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - LaunchDarkly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-02 00:00:00.000000000 Z
11
+ date: 2026-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -370,6 +370,10 @@ files:
370
370
  - lib/ldclient-rb/config.rb
371
371
  - lib/ldclient-rb/context.rb
372
372
  - lib/ldclient-rb/data_system.rb
373
+ - lib/ldclient-rb/data_system/config_builder.rb
374
+ - lib/ldclient-rb/data_system/data_source_builder_common.rb
375
+ - lib/ldclient-rb/data_system/polling_data_source_builder.rb
376
+ - lib/ldclient-rb/data_system/streaming_data_source_builder.rb
373
377
  - lib/ldclient-rb/evaluation_detail.rb
374
378
  - lib/ldclient-rb/events.rb
375
379
  - lib/ldclient-rb/flags_state.rb
@@ -392,7 +396,6 @@ files:
392
396
  - lib/ldclient-rb/impl/data_store/status_provider.rb
393
397
  - lib/ldclient-rb/impl/data_store/store.rb
394
398
  - lib/ldclient-rb/impl/data_system.rb
395
- - lib/ldclient-rb/impl/data_system/data_source_builder_common.rb
396
399
  - lib/ldclient-rb/impl/data_system/fdv1.rb
397
400
  - lib/ldclient-rb/impl/data_system/fdv2.rb
398
401
  - lib/ldclient-rb/impl/data_system/http_config_options.rb
@@ -1,77 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ldclient-rb/impl/data_system/http_config_options"
4
-
5
- module LaunchDarkly
6
- module Impl
7
- module DataSystem
8
- #
9
- # DataSourceBuilderCommon is a mixin that provides common HTTP configuration
10
- # setters for data source builders (polling and streaming).
11
- #
12
- # Each builder that includes this module must define a DEFAULT_BASE_URI constant.
13
- #
14
- module DataSourceBuilderCommon
15
- #
16
- # Sets the base URI for HTTP requests.
17
- #
18
- # @param uri [String]
19
- # @return [self]
20
- #
21
- def base_uri(uri)
22
- @base_uri = uri
23
- self
24
- end
25
-
26
- #
27
- # Sets a custom socket factory for HTTP connections.
28
- #
29
- # @param factory [Object]
30
- # @return [self]
31
- #
32
- def socket_factory(factory)
33
- @socket_factory = factory
34
- self
35
- end
36
-
37
- #
38
- # Sets the read timeout for HTTP connections.
39
- #
40
- # @param timeout [Float] Timeout in seconds
41
- # @return [self]
42
- #
43
- def read_timeout(timeout)
44
- @read_timeout = timeout
45
- self
46
- end
47
-
48
- #
49
- # Sets the connect timeout for HTTP connections.
50
- #
51
- # @param timeout [Float] Timeout in seconds
52
- # @return [self]
53
- #
54
- def connect_timeout(timeout)
55
- @connect_timeout = timeout
56
- self
57
- end
58
-
59
- #
60
- # Builds an HttpConfigOptions instance from the current builder settings.
61
- # Uses self.class::DEFAULT_BASE_URI if base_uri was not explicitly set.
62
- # Read/connect timeouts default to HttpConfigOptions defaults if not set.
63
- #
64
- # @return [HttpConfigOptions]
65
- #
66
- private def build_http_config
67
- HttpConfigOptions.new(
68
- base_uri: (@base_uri || self.class::DEFAULT_BASE_URI).chomp("/"),
69
- socket_factory: @socket_factory,
70
- read_timeout: @read_timeout,
71
- connect_timeout: @connect_timeout
72
- )
73
- end
74
- end
75
- end
76
- end
77
- end