Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 22 additions & 19 deletions lib/ldclient-rb/config.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
require "logger"
require "ldclient-rb/impl/cache_store"
require "ldclient-rb/impl/data_system/http_config_options"
require "ldclient-rb/impl/data_system/polling"
require "ldclient-rb/impl/data_system/streaming"

module LaunchDarkly
#
Expand Down Expand Up @@ -465,15 +468,15 @@ def self.default_capacity
# @return [String] "https://sdk.launchdarkly.com"
#
def self.default_base_uri
"https://sdk.launchdarkly.com"
Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_BASE_URI
end

#
# The default value for {#stream_uri}.
# @return [String] "https://stream.launchdarkly.com"
#
def self.default_stream_uri
"https://stream.launchdarkly.com"
Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_BASE_URI
end

#
Expand Down Expand Up @@ -505,23 +508,23 @@ def self.default_flush_interval
# @return [Float] 10
#
def self.default_read_timeout
10
Impl::DataSystem::HttpConfigOptions::DEFAULT_READ_TIMEOUT
end

#
# The default value for {#initial_reconnect_delay}.
# @return [Float] 1
#
def self.default_initial_reconnect_delay
1
Impl::DataSystem::StreamingDataSourceBuilder::DEFAULT_INITIAL_RECONNECT_DELAY
end

#
# The default value for {#connect_timeout}.
# @return [Float] 2
#
def self.default_connect_timeout
2
Impl::DataSystem::HttpConfigOptions::DEFAULT_CONNECT_TIMEOUT
end

#
Expand Down Expand Up @@ -575,7 +578,7 @@ def self.default_offline
# @return [Float] 30
#
def self.default_poll_interval
30
Impl::DataSystem::PollingDataSourceBuilder::DEFAULT_POLL_INTERVAL
end

#
Expand Down Expand Up @@ -699,13 +702,13 @@ def initialize(store:, context_cache_size: nil, context_cache_time: nil, status_
#
class DataSystemConfig
#
# @param initializers [Array<Proc(Config) => LaunchDarkly::Interfaces::DataSystem::Initializer>, nil] The (optional) array of builder procs
# @param primary_synchronizer [Proc(Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil] The (optional) builder proc for primary synchronizer
# @param secondary_synchronizer [Proc(Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil] The (optional) builder proc for secondary synchronizer
# @param initializers [Array<#build(String, Config)>, nil] The (optional) array of builders
# @param primary_synchronizer [#build(String, Config), nil] The (optional) builder for primary synchronizer
# @param secondary_synchronizer [#build(String, Config), nil] The (optional) builder for secondary synchronizer
# @param data_store_mode [Symbol] The (optional) data store mode
# @param data_store [LaunchDarkly::Interfaces::FeatureStore, nil] The (optional) data store
# @param fdv1_fallback_synchronizer [Proc(Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# The (optional) builder proc for FDv1-compatible fallback synchronizer
# @param fdv1_fallback_synchronizer [#build(String, Config), nil]
# The (optional) builder for FDv1-compatible fallback synchronizer
#
def initialize(initializers: nil, primary_synchronizer: nil, secondary_synchronizer: nil,
data_store_mode: LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY, data_store: nil, fdv1_fallback_synchronizer: nil)
Expand All @@ -717,16 +720,16 @@ def initialize(initializers: nil, primary_synchronizer: nil, secondary_synchroni
@fdv1_fallback_synchronizer = fdv1_fallback_synchronizer
end

# The initializers for the data system. Each proc takes sdk_key and Config and returns an Initializer.
# @return [Array<Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Initializer>, nil]
# The initializers for the data system. Each builder responds to build(sdk_key, config) and returns an Initializer.
# @return [Array<#build(String, Config)>, nil]
attr_reader :initializers

# The primary synchronizer builder. Takes sdk_key and Config and returns a Synchronizer.
# @return [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# The primary synchronizer builder. Responds to build(sdk_key, config) and returns a Synchronizer.
# @return [#build(String, Config), nil]
attr_reader :primary_synchronizer

# The secondary synchronizer builder. Takes sdk_key and Config and returns a Synchronizer.
# @return [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# The secondary synchronizer builder. Responds to build(sdk_key, config) and returns a Synchronizer.
# @return [#build(String, Config), nil]
attr_reader :secondary_synchronizer

# The data store mode.
Expand All @@ -737,8 +740,8 @@ def initialize(initializers: nil, primary_synchronizer: nil, secondary_synchroni
# @return [LaunchDarkly::Interfaces::FeatureStore, nil]
attr_reader :data_store

# The FDv1-compatible fallback synchronizer builder. Takes sdk_key and Config and returns a Synchronizer.
# @return [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# The FDv1-compatible fallback synchronizer builder. Responds to build(sdk_key, config) and returns a Synchronizer.
# @return [#build(String, Config), nil]
attr_reader :fdv1_fallback_synchronizer
end
end
36 changes: 14 additions & 22 deletions lib/ldclient-rb/data_system.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def initialize
#
# Sets the initializers for the data system.
#
# @param initializers [Array<Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Initializer>]
# Array of builder procs that take sdk_key and Config and return an Initializer
# @param initializers [Array<#build(String, Config)>]
# Array of builders that respond to build(sdk_key, config) and return an Initializer
# @return [ConfigBuilder] self for chaining
#
def initializers(initializers)
Expand All @@ -40,9 +40,8 @@ def initializers(initializers)
#
# Sets the synchronizers for the data system.
#
# @param primary [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer] Builder proc that takes sdk_key and Config and returns the primary Synchronizer
# @param secondary [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer, nil]
# Builder proc that takes sdk_key and Config and returns the secondary Synchronizer
# @param primary [#build(String, Config)] Builder that responds to build(sdk_key, config) and returns the primary Synchronizer
# @param secondary [#build(String, Config), nil] Builder that responds to build(sdk_key, config) and returns the secondary Synchronizer
# @return [ConfigBuilder] self for chaining
#
def synchronizers(primary, secondary = nil)
Expand All @@ -55,8 +54,7 @@ def synchronizers(primary, secondary = nil)
# Configures the SDK with a fallback synchronizer that is compatible with
# the Flag Delivery v1 API.
#
# @param fallback [Proc(String, Config) => LaunchDarkly::Interfaces::DataSystem::Synchronizer]
# Builder proc that takes sdk_key and Config and returns the fallback Synchronizer
# @param fallback [#build(String, Config)] Builder that responds to build(sdk_key, config) and returns the fallback Synchronizer
# @return [ConfigBuilder] self for chaining
#
def fdv1_compatible_synchronizer(fallback)
Expand Down Expand Up @@ -100,42 +98,36 @@ def build
end

#
# Returns a builder proc for creating a polling data source.
# Returns a builder for creating a polling data source.
# This is a building block that can be used with {ConfigBuilder#initializers}
# or {ConfigBuilder#synchronizers} to create custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns a polling data source
# @return [LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder]
#
def self.polling_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder.new(sdk_key, config).build
end
LaunchDarkly::Impl::DataSystem::PollingDataSourceBuilder.new
end

#
# Returns a builder proc for creating an FDv1 fallback polling data source.
# Returns a builder for creating an FDv1 fallback polling data source.
# This is a building block that can be used with {ConfigBuilder#fdv1_compatible_synchronizer}
# to provide FDv1 compatibility in custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns an FDv1 polling data source
# @return [LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder]
#
def self.fdv1_fallback_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder.new(sdk_key, config).build
end
LaunchDarkly::Impl::DataSystem::FDv1PollingDataSourceBuilder.new
end

#
# Returns a builder proc for creating a streaming data source.
# Returns a builder for creating a streaming data source.
# This is a building block that can be used with {ConfigBuilder#synchronizers}
# to create custom data system configurations.
#
# @return [Proc] A proc that takes (sdk_key, config) and returns a streaming data source
# @return [LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder]
#
def self.streaming_ds_builder
lambda do |sdk_key, config|
LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder.new(sdk_key, config).build
end
LaunchDarkly::Impl::DataSystem::StreamingDataSourceBuilder.new
end

#
Expand Down
2 changes: 1 addition & 1 deletion lib/ldclient-rb/events.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def initialize(sdk_key, config, client = nil, diagnostic_accumulator = nil, test
@inbox_full = Concurrent::AtomicBoolean.new(false)

event_sender = (test_properties || {})[:event_sender] ||
Impl::EventSender.new(sdk_key, config, client || Impl::Util.new_http_client(config.events_uri, config))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this line has made the client parameter unused. Were we ever providing this and are we appropriately capturing that level of control that we previously had?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client was actually unused in the EventSender initializer and it just constructed its own client.

Impl::EventSender.new(sdk_key, config)

@timestamp_fn = (test_properties || {})[:timestamp_fn] || proc { Impl::Util.current_time_millis }
@omit_anonymous_contexts = config.omit_anonymous_contexts
Expand Down
11 changes: 9 additions & 2 deletions lib/ldclient-rb/impl/data_source/requestor.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "ldclient-rb/impl/model/serialization"
require "ldclient-rb/impl/util"
require "ldclient-rb/impl/data_system/http_config_options"

require "concurrent/atomics"
require "json"
Expand All @@ -26,7 +27,13 @@ class Requestor
def initialize(sdk_key, config)
@sdk_key = sdk_key
@config = config
@http_client = Impl::Util.new_http_client(config.base_uri, config)
@http_config = DataSystem::HttpConfigOptions.new(
base_uri: config.base_uri,
socket_factory: config.socket_factory,
read_timeout: config.read_timeout,
connect_timeout: config.connect_timeout
)
@http_client = Impl::Util.new_http_client(@http_config)
.use(:auto_inflate)
.headers("Accept-Encoding" => "gzip")
@cache = @config.cache_store
Expand All @@ -48,7 +55,7 @@ def stop

def make_request(path)
uri = URI(
Util.add_payload_filter_key(@config.base_uri + path, @config)
Util.add_payload_filter_key(@http_config.base_uri + path, @config)
)
headers = {}
Impl::Util.default_http_headers(@sdk_key, @config).each { |k, v| headers[k] = v }
Expand Down
79 changes: 79 additions & 0 deletions lib/ldclient-rb/impl/data_system/data_source_builder_common.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

require "ldclient-rb/impl/data_system/http_config_options"

module LaunchDarkly
module Impl
module DataSystem
#
# DataSourceBuilderCommon is a mixin that provides common HTTP configuration
# setters for data source builders (polling and streaming).
#
# Each builder that includes this module must define a DEFAULT_BASE_URI constant.
#
module DataSourceBuilderCommon
#
# Sets the base URI for HTTP requests.
#
# @param uri [String]
# @return [self]
#
def base_uri(uri)
@base_uri = uri
self
end

#
# Sets a custom socket factory for HTTP connections.
#
# @param factory [Object]
# @return [self]
#
def socket_factory(factory)
@socket_factory = factory
self
end

#
# Sets the read timeout for HTTP connections.
#
# @param timeout [Float] Timeout in seconds
# @return [self]
#
def read_timeout(timeout)
@read_timeout = timeout
self
end

#
# Sets the connect timeout for HTTP connections.
#
# @param timeout [Float] Timeout in seconds
# @return [self]
#
def connect_timeout(timeout)
@connect_timeout = timeout
self
end

private
Comment thread
jsonbailey marked this conversation as resolved.
Outdated

#
# Builds an HttpConfigOptions instance from the current builder settings.
# Uses self.class::DEFAULT_BASE_URI if base_uri was not explicitly set.
# Read/connect timeouts default to HttpConfigOptions defaults if not set.
#
# @return [HttpConfigOptions]
#
def build_http_config
HttpConfigOptions.new(
base_uri: @base_uri || self.class::DEFAULT_BASE_URI,
socket_factory: @socket_factory,
read_timeout: @read_timeout,
connect_timeout: @connect_timeout
)
end
end
end
end
end
6 changes: 3 additions & 3 deletions lib/ldclient-rb/impl/data_system/fdv2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def run_initializers
return if @stop_event.set?

begin
initializer = initializer_builder.call(@sdk_key, @config)
initializer = initializer_builder.build(@sdk_key, @config)
@logger.info { "[LDClient] Attempting to initialize via #{initializer.name}" }

basis_result = initializer.fetch(@store)
Expand Down Expand Up @@ -269,7 +269,7 @@ def synchronizer_loop
# Try primary synchronizer
begin
@lock.synchronize do
primary_sync = @primary_synchronizer_builder.call(@sdk_key, @config)
primary_sync = @primary_synchronizer_builder.build(@sdk_key, @config)
if primary_sync.respond_to?(:set_diagnostic_accumulator) && @diagnostic_accumulator
primary_sync.set_diagnostic_accumulator(@diagnostic_accumulator)
end
Expand Down Expand Up @@ -304,7 +304,7 @@ def synchronizer_loop
next if @secondary_synchronizer_builder.nil?

@lock.synchronize do
secondary_sync = @secondary_synchronizer_builder.call(@sdk_key, @config)
secondary_sync = @secondary_synchronizer_builder.build(@sdk_key, @config)
if secondary_sync.respond_to?(:set_diagnostic_accumulator) && @diagnostic_accumulator
secondary_sync.set_diagnostic_accumulator(@diagnostic_accumulator)
end
Expand Down
32 changes: 32 additions & 0 deletions lib/ldclient-rb/impl/data_system/http_config_options.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module LaunchDarkly
module Impl
module DataSystem
#
# HttpConfigOptions contains HTTP connection configuration settings.
# This class is created by data source builders and passed to v2 Requesters/DataSources.
#
class HttpConfigOptions
# Generic HTTP defaults - base URIs live in the respective builders
DEFAULT_READ_TIMEOUT = 10
DEFAULT_CONNECT_TIMEOUT = 2

attr_reader :base_uri, :socket_factory, :read_timeout, :connect_timeout

#
# @param base_uri [String] The base URI for HTTP requests
# @param socket_factory [Object, nil] Optional socket factory for custom connections
# @param read_timeout [Float, nil] Read timeout in seconds (defaults to DEFAULT_READ_TIMEOUT)
# @param connect_timeout [Float, nil] Connect timeout in seconds (defaults to DEFAULT_CONNECT_TIMEOUT)
#
def initialize(base_uri:, socket_factory: nil, read_timeout: nil, connect_timeout: nil)
@base_uri = base_uri
@socket_factory = socket_factory
@read_timeout = read_timeout || DEFAULT_READ_TIMEOUT
@connect_timeout = connect_timeout || DEFAULT_CONNECT_TIMEOUT
end
end
end
end
end
Loading