diff --git a/.github/actions/check/action.yml b/.github/actions/check/action.yml index e86e157a..a1290210 100644 --- a/.github/actions/check/action.yml +++ b/.github/actions/check/action.yml @@ -51,4 +51,4 @@ runs: test_service_port: 9000 enable_persistence_tests: true token: ${{ inputs.token }} - version: v3.0.0-alpha.2 \ No newline at end of file + version: v3.0.0-alpha.3 \ No newline at end of file diff --git a/contract-tests/client_entity.rb b/contract-tests/client_entity.rb index 11c8e121..1b6570f9 100644 --- a/contract-tests/client_entity.rb +++ b/contract-tests/client_entity.rb @@ -37,20 +37,13 @@ def initialize(log, config) data_system.initializers(initializers) end - sync_config = data_system_config[:synchronizers] - if sync_config - primary = sync_config[:primary] - secondary = sync_config[:secondary] + sync_configs = data_system_config[:synchronizers] + if sync_configs && !sync_configs.empty? + synchronizer_builders = sync_configs.map { |sync_config| build_synchronizer_builder(sync_config) }.compact + data_system.synchronizers(synchronizer_builders) unless synchronizer_builders.empty? - primary_builder = build_synchronizer_builder(primary) - secondary_builder = build_synchronizer_builder(secondary) - - data_system.synchronizers(primary_builder, secondary_builder) if primary_builder - - if primary_builder || secondary_builder - fallback_builder = build_fdv1_fallback_builder(primary, secondary) - data_system.fdv1_compatible_synchronizer(fallback_builder) - end + fallback_builder = build_fdv1_fallback_builder(sync_configs) + data_system.fdv1_compatible_synchronizer(fallback_builder) end if data_system_config[:payloadFilter] @@ -327,17 +320,16 @@ def close end # - # Builds an FDv1 fallback polling data source builder using the first available config. + # Builds an FDv1 fallback polling data source builder using the first available polling config. # - # @param primary [Hash, nil] The primary synchronizer configuration - # @param secondary [Hash, nil] The secondary synchronizer configuration + # @param sync_configs [Array] Array of synchronizer configurations # @return [Object] Returns the configured FDv1 fallback builder # - private def build_fdv1_fallback_builder(primary, secondary) + private def build_fdv1_fallback_builder(sync_configs) builder = LaunchDarkly::DataSystem.fdv1_fallback_ds_builder # Use the first available polling config for the fallback base_uri - polling_config = primary&.dig(:polling) || secondary&.dig(:polling) + polling_config = sync_configs.lazy.map { |c| c[:polling] }.detect { |p| p } if polling_config builder.base_uri(polling_config[:baseUri]) if polling_config[:baseUri] builder.poll_interval(polling_config[:pollIntervalMs] / 1_000.0) if polling_config[:pollIntervalMs] diff --git a/lib/ldclient-rb/config.rb b/lib/ldclient-rb/config.rb index f82860b0..aa4d1d67 100644 --- a/lib/ldclient-rb/config.rb +++ b/lib/ldclient-rb/config.rb @@ -703,34 +703,28 @@ def initialize(store:, context_cache_size: nil, context_cache_time: nil, status_ class DataSystemConfig # # @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 synchronizers [Array<#build(String, Config)>, nil] The (optional) array of synchronizer builders # @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 [#build(String, Config), nil] # The (optional) builder for FDv1-compatible fallback synchronizer # - def initialize(initializers: nil, primary_synchronizer: nil, secondary_synchronizer: nil, + def initialize(initializers: nil, synchronizers: nil, data_store_mode: LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY, data_store: nil, fdv1_fallback_synchronizer: nil) @initializers = initializers - @primary_synchronizer = primary_synchronizer - @secondary_synchronizer = secondary_synchronizer + @synchronizers = synchronizers @data_store_mode = data_store_mode @data_store = data_store @fdv1_fallback_synchronizer = fdv1_fallback_synchronizer end - # The initializers for the data system. Each builder responds to build(sdk_key, config) and returns an Initializer. + # The initializer builders 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. Responds to build(sdk_key, config) and returns a Synchronizer. - # @return [#build(String, Config), nil] - attr_reader :primary_synchronizer - - # The secondary synchronizer builder. Responds to build(sdk_key, config) and returns a Synchronizer. - # @return [#build(String, Config), nil] - attr_reader :secondary_synchronizer + # The synchronizer builders for the data system. Each builder responds to build(sdk_key, config) and returns a Synchronizer. + # @return [Array<#build(String, Config)>, nil] + attr_reader :synchronizers # The data store mode. # @return [Symbol] diff --git a/lib/ldclient-rb/data_system.rb b/lib/ldclient-rb/data_system.rb index 2e002b63..faed96a8 100644 --- a/lib/ldclient-rb/data_system.rb +++ b/lib/ldclient-rb/data_system.rb @@ -18,8 +18,7 @@ module DataSystem class ConfigBuilder def initialize @initializers = nil - @primary_synchronizer = nil - @secondary_synchronizer = nil + @synchronizers = nil @fdv1_fallback_synchronizer = nil @data_store_mode = LaunchDarkly::Interfaces::DataSystem::DataStoreMode::READ_ONLY @data_store = nil @@ -40,13 +39,12 @@ def initializers(initializers) # # Sets the synchronizers for the data system. # - # @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 + # @param synchronizers [Array<#build(String, Config)>] + # Array of builders that respond to build(sdk_key, config) and return a Synchronizer # @return [ConfigBuilder] self for chaining # - def synchronizers(primary, secondary = nil) - @primary_synchronizer = primary - @secondary_synchronizer = secondary + def synchronizers(synchronizers) + @synchronizers = synchronizers self end @@ -79,17 +77,11 @@ def data_store(data_store, store_mode) # Builds the data system configuration. # # @return [DataSystemConfig] - # @raise [ArgumentError] if configuration is invalid # def build - if @secondary_synchronizer && @primary_synchronizer.nil? - raise ArgumentError, "Primary synchronizer must be set if secondary is set" - end - DataSystemConfig.new( initializers: @initializers, - primary_synchronizer: @primary_synchronizer, - secondary_synchronizer: @secondary_synchronizer, + synchronizers: @synchronizers, data_store_mode: @data_store_mode, data_store: @data_store, fdv1_fallback_synchronizer: @fdv1_fallback_synchronizer @@ -151,7 +143,7 @@ def self.default builder = ConfigBuilder.new builder.initializers([polling_builder]) - builder.synchronizers(streaming_builder, polling_builder) + builder.synchronizers([streaming_builder, polling_builder]) builder.fdv1_compatible_synchronizer(fallback) builder @@ -169,7 +161,7 @@ def self.streaming fallback = fdv1_fallback_ds_builder builder = ConfigBuilder.new - builder.synchronizers(streaming_builder) + builder.synchronizers([streaming_builder]) builder.fdv1_compatible_synchronizer(fallback) builder @@ -187,7 +179,7 @@ def self.polling fallback = fdv1_fallback_ds_builder builder = ConfigBuilder.new - builder.synchronizers(polling_builder) + builder.synchronizers([polling_builder]) builder.fdv1_compatible_synchronizer(fallback) builder diff --git a/lib/ldclient-rb/impl/data_source/status_provider.rb b/lib/ldclient-rb/impl/data_source/status_provider.rb index 087e15c0..ec55cd36 100644 --- a/lib/ldclient-rb/impl/data_source/status_provider.rb +++ b/lib/ldclient-rb/impl/data_source/status_provider.rb @@ -54,6 +54,11 @@ def update_status(new_state, new_error) new_state = LaunchDarkly::Interfaces::DataSource::Status::INITIALIZING end + # Special handling: You can't go back to INITIALIZING after being anything else + if new_state == LaunchDarkly::Interfaces::DataSource::Status::INITIALIZING && !old_status.state.nil? + new_state = old_status.state + end + # No change if state is the same and no error return if new_state == old_status.state && new_error.nil? diff --git a/lib/ldclient-rb/impl/data_store/status_provider.rb b/lib/ldclient-rb/impl/data_store/status_provider.rb index fda0bf08..deae9ee0 100644 --- a/lib/ldclient-rb/impl/data_store/status_provider.rb +++ b/lib/ldclient-rb/impl/data_store/status_provider.rb @@ -10,12 +10,6 @@ module DataStore # # StatusProviderV2 is the FDv2-specific implementation of {LaunchDarkly::Interfaces::DataStore::StatusProvider}. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. - # class StatusProviderV2 include LaunchDarkly::Interfaces::DataStore::StatusProvider diff --git a/lib/ldclient-rb/impl/data_system/fdv2.rb b/lib/ldclient-rb/impl/data_system/fdv2.rb index 5fa0631f..0194cc35 100644 --- a/lib/ldclient-rb/impl/data_system/fdv2.rb +++ b/lib/ldclient-rb/impl/data_system/fdv2.rb @@ -14,6 +14,30 @@ module LaunchDarkly module Impl module DataSystem + # + # Represents the possible outcomes from consuming synchronizer results. + # + # Used by {FDv2#consume_synchronizer_results} to indicate what action the + # synchronizer loop should take next. + # + module SyncResult + # Temporarily move to the next synchronizer in the list. + # The current synchronizer remains available for future recovery. + FALLBACK = :fallback + + # Return to the first synchronizer in the list. + # Used when recovery conditions are met on a fallback synchronizer. + RECOVER = :recover + + # Permanently remove the current synchronizer from the list. + # Used for unrecoverable failures (OFF state, exceptions). + REMOVE = :remove + + # Switch to the FDv1 protocol fallback. + # Replaces the synchronizer list with the FDv1 fallback synchronizer. + FDV1 = :fdv1 + end + # FDv2 is an implementation of the DataSystem interface that uses the Flag Delivery V2 protocol # for obtaining and keeping data up-to-date. Additionally, it operates with an optional persistent # store in read-only or read/write mode. @@ -30,8 +54,7 @@ def initialize(sdk_key, config, data_system_config) @config = config @data_system_config = data_system_config @logger = config.logger - @primary_synchronizer_builder = data_system_config.primary_synchronizer - @secondary_synchronizer_builder = data_system_config.secondary_synchronizer + @synchronizer_builders = data_system_config.synchronizers || [] @fdv1_fallback_synchronizer_builder = data_system_config.fdv1_fallback_synchronizer @disabled = @config.offline? @@ -86,7 +109,7 @@ def initialize(sdk_key, config, data_system_config) # Track configuration @configured_with_data_sources = (@data_system_config.initializers && !@data_system_config.initializers.empty?) || - !@data_system_config.primary_synchronizer.nil? + !@synchronizer_builders.empty? end # (see DataSystem#start) @@ -246,8 +269,8 @@ def run_initializers # @return [void] # def run_synchronizers - # If no primary synchronizer configured, just set ready and return - if @primary_synchronizer_builder.nil? + # If no synchronizers configured, just set ready and return + if @synchronizer_builders.empty? @ready_event.set return end @@ -259,79 +282,64 @@ def run_synchronizers end # - # Synchronizer loop that manages primary/secondary/fallback synchronizers. + # Synchronizer loop that manages synchronizers and fallbacks. # # @return [void] # def synchronizer_loop + # Track the current index in the synchronizer array + current_index = 0 + begin - while !@stop_event.set? && @primary_synchronizer_builder - # Try primary synchronizer + while !@stop_event.set? && current_index < @synchronizer_builders.length + synchronizer_builder = @synchronizer_builders[current_index] + is_primary = current_index == 0 + begin @lock.synchronize do - 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) + sync = synchronizer_builder.build(@sdk_key, @config) + if sync.respond_to?(:set_diagnostic_accumulator) && @diagnostic_accumulator + sync.set_diagnostic_accumulator(@diagnostic_accumulator) end - @active_synchronizer = primary_sync + @active_synchronizer = sync end - @logger.info { "[LDClient] Primary synchronizer #{@active_synchronizer.name} is starting" } + @logger.info { "[LDClient] Synchronizer[#{current_index}] #{@active_synchronizer.name} is starting" } - remove_sync, fallback_v1 = consume_synchronizer_results( - @active_synchronizer, - method(:fallback_condition) - ) + sync_result = consume_synchronizer_results(@active_synchronizer, check_recovery: !is_primary) - if remove_sync - @primary_synchronizer_builder = fallback_v1 ? @fdv1_fallback_synchronizer_builder : @secondary_synchronizer_builder - @secondary_synchronizer_builder = nil + break if @stop_event.set? - if @primary_synchronizer_builder.nil? - @logger.warn { "[LDClient] No more synchronizers available" } - @data_source_status_provider.update_status( - LaunchDarkly::Interfaces::DataSource::Status::OFF, - @data_source_status_provider.status.last_error - ) - break + case sync_result + when SyncResult::FDV1 + if @fdv1_fallback_synchronizer_builder + @synchronizer_builders = [@fdv1_fallback_synchronizer_builder] + current_index = 0 + next end + # No FDv1 fallback configured, treat as regular fallback + current_index += 1 + when SyncResult::RECOVER + @logger.info { "[LDClient] Recovery condition met, returning to primary synchronizer" } + current_index = 0 + when SyncResult::REMOVE + @logger.info { "[LDClient] Removing synchronizer from list due to permanent failure" } + @synchronizer_builders.delete_at(current_index) else @logger.info { "[LDClient] Fallback condition met" } + current_index += 1 end - break if @stop_event.set? - - next if @secondary_synchronizer_builder.nil? - - @lock.synchronize do - 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 - @logger.info { "[LDClient] Secondary synchronizer #{secondary_sync.name} is starting" } - @active_synchronizer = secondary_sync - end + current_index = 0 if current_index >= @synchronizer_builders.length - remove_sync, fallback_v1 = consume_synchronizer_results( - @active_synchronizer, - method(:recovery_condition) - ) - - if remove_sync - @secondary_synchronizer_builder = nil - @primary_synchronizer_builder = @fdv1_fallback_synchronizer_builder if fallback_v1 - - if @primary_synchronizer_builder.nil? - @logger.warn { "[LDClient] No more synchronizers available" } - @data_source_status_provider.update_status( - LaunchDarkly::Interfaces::DataSource::Status::OFF, - @data_source_status_provider.status.last_error - ) - break - end + if @synchronizer_builders.length == 0 + @logger.warn { "[LDClient] No more synchronizers available" } + @data_source_status_provider.update_status( + LaunchDarkly::Interfaces::DataSource::Status::OFF, + @data_source_status_provider.status.last_error + ) + break end - - @logger.info { "[LDClient] Recovery condition met, returning to primary synchronizer" } rescue => e @logger.error { "[LDClient] Failed to build synchronizer: #{e.message}" } break @@ -353,10 +361,10 @@ def synchronizer_loop # Consume results from a synchronizer until a condition is met or it fails. # # @param synchronizer [Object] The synchronizer - # @param condition_func [Proc] Function to check if condition is met - # @return [Array(Boolean, Boolean)] [should_remove_sync, fallback_to_fdv1] + # @param check_recovery [Boolean] Whether to check recovery condition (healthy too long) + # @return [Symbol] One of {SyncResult::FALLBACK}, {SyncResult::RECOVER}, {SyncResult::REMOVE}, or {SyncResult::FDV1} # - def consume_synchronizer_results(synchronizer, condition_func) + def consume_synchronizer_results(synchronizer, check_recovery: false) action_queue = Queue.new timer = LaunchDarkly::Impl::RepeatingTask.new(10, 10, -> { action_queue.push("check") }, @logger, "FDv2-sync-cond-timer") @@ -384,13 +392,14 @@ def consume_synchronizer_results(synchronizer, condition_func) if update == "check" # Check condition periodically current_status = @data_source_status_provider.status - return [false, false] if condition_func.call(current_status) + return SyncResult::RECOVER if check_recovery && recovery_condition(current_status) + return SyncResult::FALLBACK if fallback_condition(current_status) end next end @logger.info { "[LDClient] Synchronizer #{synchronizer.name} update: #{update.state}" } - return [false, false] if @stop_event.set? + return SyncResult::FALLBACK if @stop_event.set? # Handle the update @store.apply(update.change_set, true) if update.change_set @@ -401,26 +410,24 @@ def consume_synchronizer_results(synchronizer, condition_func) # Update status @data_source_status_provider.update_status(update.state, update.error) - # Check if we should revert to FDv1 immediately - return [true, true] if update.revert_to_fdv1 + return SyncResult::FDV1 if update.revert_to_fdv1 - # Check for OFF state indicating permanent failure - return [true, false] if update.state == LaunchDarkly::Interfaces::DataSource::Status::OFF + return SyncResult::REMOVE if update.state == LaunchDarkly::Interfaces::DataSource::Status::OFF end rescue => e @logger.error { "[LDClient] Error consuming synchronizer results: #{e.message}" } - return [true, false] + return SyncResult::REMOVE ensure synchronizer.stop timer.stop sync_reader.join(0.5) if sync_reader.alive? end - [true, false] + SyncResult::REMOVE end # - # Determine if we should fallback to secondary synchronizer. + # Determine if we should fallback to the next synchronizer. # # @param status [LaunchDarkly::Interfaces::DataSource::Status] Current data source status # @return [Boolean] true if fallback condition is met @@ -435,20 +442,14 @@ def fallback_condition(status) end # - # Determine if we should try to recover to primary synchronizer. + # Determine if we should recover to the primary synchronizer. # # @param status [LaunchDarkly::Interfaces::DataSource::Status] Current data source status - # @return [Boolean] true if recovery condition is met + # @return [Boolean] true if recovery condition is met (healthy for too long) # def recovery_condition(status) - interrupted_at_runtime = status.state == LaunchDarkly::Interfaces::DataSource::Status::INTERRUPTED && - Time.now - status.state_since > 60 # 1 minute - healthy_for_too_long = status.state == LaunchDarkly::Interfaces::DataSource::Status::VALID && + status.state == LaunchDarkly::Interfaces::DataSource::Status::VALID && Time.now - status.state_since > 300 # 5 minutes - cannot_initialize = status.state == LaunchDarkly::Interfaces::DataSource::Status::INITIALIZING && - Time.now - status.state_since > 10 # 10 seconds - - interrupted_at_runtime || healthy_for_too_long || cannot_initialize end # diff --git a/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb b/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb index eded0ad8..b1153992 100644 --- a/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb +++ b/lib/ldclient-rb/impl/integrations/file_data_source_v2.rb @@ -16,12 +16,6 @@ module Integrations # # Internal implementation of both Initializer and Synchronizer protocols for file-based data. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. - # # This component reads feature flag and segment data from local files and provides them # via the FDv2 protocol interfaces. Each instance implements both Initializer and Synchronizer # protocols: diff --git a/lib/ldclient-rb/integrations/file_data.rb b/lib/ldclient-rb/integrations/file_data.rb index fe29f0c8..256c360a 100644 --- a/lib/ldclient-rb/integrations/file_data.rb +++ b/lib/ldclient-rb/integrations/file_data.rb @@ -108,11 +108,8 @@ def self.data_source(options={}) # # Returns a builder for the FDv2-compatible file data source. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This method is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # # This method returns a builder proc that can be used with the FDv2 data system # configuration as both an Initializer and a Synchronizer. When used as an Initializer @@ -137,7 +134,7 @@ def self.data_source(options={}) # @example Using as a synchronizer # file_source = LaunchDarkly::Integrations::FileData.data_source_v2(paths: ['flags.json']) # data_system_config = LaunchDarkly::DataSystemConfig.new( - # synchronizer: file_source + # synchronizers: [file_source] # ) # config = LaunchDarkly::Config.new(data_system: data_system_config) # @@ -145,7 +142,7 @@ def self.data_source(options={}) # file_source = LaunchDarkly::Integrations::FileData.data_source_v2(paths: ['flags.json']) # data_system_config = LaunchDarkly::DataSystemConfig.new( # initializers: [file_source], - # synchronizer: file_source + # synchronizers: [file_source] # ) # config = LaunchDarkly::Config.new(data_system: data_system_config) # diff --git a/lib/ldclient-rb/integrations/test_data_v2.rb b/lib/ldclient-rb/integrations/test_data_v2.rb index cddd73ae..52ed6500 100644 --- a/lib/ldclient-rb/integrations/test_data_v2.rb +++ b/lib/ldclient-rb/integrations/test_data_v2.rb @@ -9,11 +9,8 @@ module Integrations # A mechanism for providing dynamically updatable feature flag state in a # simplified form to an SDK client in test scenarios using the FDv2 protocol. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This class is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # # Unlike {LaunchDarkly::Integrations::FileData}, this mechanism does not use any external resources. It # provides only the data that the application has put into it using the {#update} method. diff --git a/lib/ldclient-rb/interfaces/data_system.rb b/lib/ldclient-rb/interfaces/data_system.rb index 6447dc80..92479b75 100644 --- a/lib/ldclient-rb/interfaces/data_system.rb +++ b/lib/ldclient-rb/interfaces/data_system.rb @@ -6,11 +6,8 @@ module DataSystem # # EventName represents the name of an event that can be sent by the server for FDv2. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module EventName # Specifies that an object should be added to the data set with upsert semantics. @@ -38,11 +35,8 @@ module EventName # # ObjectKind represents the kind of object. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module ObjectKind # Represents a feature flag. @@ -55,11 +49,8 @@ module ObjectKind # # ChangeType specifies if an object is being upserted or deleted. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module ChangeType # Represents an object being upserted. @@ -72,11 +63,8 @@ module ChangeType # # IntentCode represents the various intents that can be sent by the server. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module IntentCode # The server intends to send a full data set. @@ -92,11 +80,8 @@ module IntentCode # # DataStoreMode represents the mode of operation of a Data Store in FDV2 mode. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module DataStoreMode # Indicates that the data store is read-only. Data will never be written back to the store by the SDK. @@ -110,11 +95,8 @@ module DataStoreMode # # Selector represents a particular snapshot of data. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class Selector # @return [String] The state @@ -214,11 +196,8 @@ def hash # # Change represents a change to a piece of data, such as an update or deletion. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class Change # @return [String] The action ({ChangeType}) @@ -255,11 +234,8 @@ def initialize(action:, kind:, key:, version:, object: nil) # # ChangeSet represents a list of changes to be applied. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class ChangeSet # @return [String] The intent code ({IntentCode}) @@ -286,11 +262,8 @@ def initialize(intent_code:, changes:, selector:) # # Basis represents the initial payload of data that a data source can provide. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class Basis # @return [ChangeSet] The change set @@ -317,11 +290,8 @@ def initialize(change_set:, persist:, environment_id: nil) # # Payload represents a payload delivered in a streaming response. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class Payload # @return [String] The payload ID @@ -387,11 +357,8 @@ def self.from_h(data) # # ServerIntent represents the type of change associated with the payload. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class ServerIntent # @return [Payload] The payload @@ -438,11 +405,8 @@ def self.from_h(data) # # ChangeSetBuilder is a helper for constructing a ChangeSet. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class ChangeSetBuilder # @return [String, nil] The current intent ({IntentCode}) @@ -582,11 +546,8 @@ def add_delete(kind, key, version) # # Update represents the results of a synchronizer's ongoing sync method. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # class Update # @return [Symbol] The data source state ({LaunchDarkly::Interfaces::DataSource::Status}) @@ -623,11 +584,8 @@ def initialize(state:, change_set: nil, error: nil, revert_to_fdv1: false, envir # # SelectorStore represents a component capable of providing Selectors for data retrieval. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module SelectorStore # @@ -643,11 +601,8 @@ def selector # # ReadOnlyStore represents a read-only store interface for retrieving data. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module ReadOnlyStore # @@ -684,11 +639,8 @@ def initialized? # # Initializer represents a component capable of retrieving a single data result. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module Initializer # @@ -714,11 +666,8 @@ def fetch(selector_store) # # Synchronizer represents a component capable of synchronizing data from an external source. # - # This type is not stable, and not subject to any backwards - # compatibility guarantees or semantic versioning. It is not suitable for production usage. - # - # Do not use it. - # You have been warned. + # This type is not stable, and not subject to any backwards compatibility guarantees or semantic versioning. + # It is in early access. If you want access to this feature please join the EAP. https://launchdarkly.com/docs/sdk/features/data-saving-mode # module Synchronizer # diff --git a/spec/impl/data_system/fdv2_datasystem_spec.rb b/spec/impl/data_system/fdv2_datasystem_spec.rb index 488a0fd9..44c85548 100644 --- a/spec/impl/data_system/fdv2_datasystem_spec.rb +++ b/spec/impl/data_system/fdv2_datasystem_spec.rb @@ -36,7 +36,7 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers([td_initializer.test_data_ds_builder]) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .build fdv2 = FDv2.new(sdk_key, config, data_system_config) @@ -78,7 +78,7 @@ def build(_sdk_key, _config) td = LaunchDarkly::Integrations::TestDataV2.data_source data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td.test_data_ds_builder) + .synchronizers([td.test_data_ds_builder]) .build fdv2 = FDv2.new(sdk_key, config, data_system_config) @@ -110,7 +110,7 @@ def build(_sdk_key, _config) td = LaunchDarkly::Integrations::TestDataV2.data_source data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td.test_data_ds_builder) + .synchronizers([td.test_data_ds_builder]) .build fdv2 = FDv2.new(sdk_key, config, data_system_config) @@ -139,9 +139,10 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers([td.test_data_ds_builder]) .synchronizers( - MockBuilder.new(mock_primary), - td.test_data_ds_builder - ) + [ + MockBuilder.new(mock_primary), + td.test_data_ds_builder, + ]) .build changed = Concurrent::Event.new @@ -192,9 +193,10 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers([td.test_data_ds_builder]) .synchronizers( - MockBuilder.new(mock_primary), - MockBuilder.new(mock_secondary) - ) + [ + MockBuilder.new(mock_primary), + MockBuilder.new(mock_secondary), + ]) .build changed = Concurrent::Event.new @@ -236,7 +238,7 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(MockBuilder.new(mock_primary)) + .synchronizers([MockBuilder.new(mock_primary)]) .fdv1_compatible_synchronizer(td_fdv1.test_data_ds_builder) .build @@ -285,7 +287,7 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(MockBuilder.new(mock_primary)) + .synchronizers([MockBuilder.new(mock_primary)]) .fdv1_compatible_synchronizer(td_fdv1.test_data_ds_builder) .build @@ -345,7 +347,7 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers([td_initializer.test_data_ds_builder]) - .synchronizers(MockBuilder.new(mock_primary)) + .synchronizers([MockBuilder.new(mock_primary)]) .fdv1_compatible_synchronizer(td_fdv1.test_data_ds_builder) .build @@ -404,9 +406,10 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) .synchronizers( - MockBuilder.new(mock_primary), - MockBuilder.new(mock_secondary) - ) + [ + MockBuilder.new(mock_primary), + MockBuilder.new(mock_secondary), + ]) .fdv1_compatible_synchronizer(td_fdv1.test_data_ds_builder) .build @@ -444,7 +447,7 @@ def build(_sdk_key, _config) data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(MockBuilder.new(mock_primary)) + .synchronizers([MockBuilder.new(mock_primary)]) .fdv1_compatible_synchronizer(td_fdv1.test_data_ds_builder) .build diff --git a/spec/impl/data_system/fdv2_persistence_spec.rb b/spec/impl/data_system/fdv2_persistence_spec.rb index 5ce1c075..8eee67cc 100644 --- a/spec/impl/data_system/fdv2_persistence_spec.rb +++ b/spec/impl/data_system/fdv2_persistence_spec.rb @@ -124,7 +124,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -180,7 +180,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -210,7 +210,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -240,7 +240,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -283,7 +283,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_only) .build @@ -307,7 +307,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -353,7 +353,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_only) .build @@ -401,7 +401,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers([td_initializer.test_data_ds_builder]) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -440,7 +440,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(persistent_store, :read_write) .build @@ -467,7 +467,7 @@ def get_data_snapshot data_system_config = LaunchDarkly::DataSystem::ConfigBuilder.new .initializers(nil) - .synchronizers(td_synchronizer.test_data_ds_builder) + .synchronizers([td_synchronizer.test_data_ds_builder]) .data_store(nil, :read_write) # No persistent store .build