Class: LaunchDarkly::Impl::DataSystem::FDv2 Private

Inherits:
Object
  • Object
show all
Includes:
LaunchDarkly::Impl::DataSystem
Defined in:
lib/ldclient-rb/impl/data_system/fdv2.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

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.

Since:

  • 5.5.0

Constant Summary

Constants included from LaunchDarkly::Impl::DataSystem

FDV1_POLLING_ENDPOINT, FDV2_POLLING_ENDPOINT, FDV2_STREAMING_ENDPOINT, LD_ENVID_HEADER, LD_FD_FALLBACK_HEADER, STREAM_READ_TIMEOUT

Instance Method Summary collapse

Methods included from LaunchDarkly::Impl::DataSystem

fdv1_polling_payload_to_changeset, polling_payload_to_changeset

Constructor Details

#initialize(sdk_key, config, data_system_config) ⇒ FDv2

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize a new FDv2 data system.

Since:

  • 5.5.0



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 52

def initialize(sdk_key, config, data_system_config)
  @sdk_key = sdk_key
  @config = config
  @data_system_config = data_system_config
  @logger = config.logger
  @synchronizer_builders = data_system_config.synchronizers || []
  @fdv1_fallback_synchronizer_builder = data_system_config.fdv1_fallback_synchronizer
  @disabled = @config.offline?

  # Diagnostic accumulator provided by client for streaming metrics
  @diagnostic_accumulator = nil

  # Shared executor for all broadcasters
  @shared_executor = Concurrent::SingleThreadExecutor.new

  # Set up event listeners
  @flag_change_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @logger)
  @change_set_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @logger)
  @data_source_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @logger)
  @data_store_broadcaster = LaunchDarkly::Impl::Broadcaster.new(@shared_executor, @logger)

  recovery_listener = Object.new
  recovery_listener.define_singleton_method(:update) do |data_store_status|
    persistent_store_outage_recovery(data_store_status)
  end
  @data_store_broadcaster.add_listener(recovery_listener)

  # Create the store
  @store = LaunchDarkly::Impl::DataStore::Store.new(@flag_change_broadcaster, @change_set_broadcaster, @logger)

  # Status providers
  @data_source_status_provider = LaunchDarkly::Impl::DataSource::StatusProviderV2.new(
    @data_source_broadcaster
  )
  @data_store_status_provider = LaunchDarkly::Impl::DataStore::StatusProviderV2.new(nil, @data_store_broadcaster)

  # Configure persistent store if provided
  if @data_system_config.data_store
    @data_store_status_provider = LaunchDarkly::Impl::DataStore::StatusProviderV2.new(
      @data_system_config.data_store,
      @data_store_broadcaster
    )
    writable = @data_system_config.data_store_mode == :read_write
    wrapper = LaunchDarkly::Impl::DataStore::FeatureStoreClientWrapperV2.new(
      @data_system_config.data_store,
      @data_store_status_provider,
      @logger
    )
    @store.with_persistence(wrapper, writable, @data_store_status_provider)
  end

  # Threading
  @stop_event = Concurrent::Event.new
  @ready_event = Concurrent::Event.new
  @lock = Mutex.new
  @active_synchronizer = nil
  @threads = []

  # Track configuration
  @configured_with_data_sources = (@data_system_config.initializers && !@data_system_config.initializers.empty?) ||
    !@synchronizer_builders.empty?
end

Instance Method Details

#data_availabilitySymbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Indicates what form of data is currently available.

This is calculated dynamically based on current system state.

Since:

  • 5.5.0



189
190
191
192
193
194
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 189

def data_availability
  return DataAvailability::REFRESHED if @store.selector.defined?
  return DataAvailability::CACHED if !@configured_with_data_sources || @store.initialized?

  DataAvailability::DEFAULTS
end

#data_source_status_providerLaunchDarkly::Interfaces::DataSource::StatusProvider

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns an interface for tracking the status of the data source.

The data source is the mechanism that the SDK uses to get feature flag configurations, such as a streaming connection (the default) or poll requests.

Since:

  • 5.5.0



174
175
176
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 174

def data_source_status_provider
  @data_source_status_provider
end

#data_store_status_providerLaunchDarkly::Interfaces::DataStore::StatusProvider

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns an interface for tracking the status of a persistent data store.

The provider has methods for checking whether the data store is (as far as the SDK knows) currently operational, tracking changes in this status, and getting cache statistics. These are only relevant for a persistent data store; if you are using an in-memory data store, then this method will return a stub object that provides no information.

Since:

  • 5.5.0



179
180
181
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 179

def data_store_status_provider
  @data_store_status_provider
end

#flag_change_broadcasterLaunchDarkly::Impl::Broadcaster

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the broadcaster for flag change notifications.

Consumers can use this broadcaster to build their own flag tracker or listen for flag changes directly.

Since:

  • 5.5.0



184
185
186
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 184

def flag_change_broadcaster
  @flag_change_broadcaster
end

#set_diagnostic_accumulator(diagnostic_accumulator) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Sets the diagnostic accumulator for streaming initialization metrics. This should be called before start() to ensure metrics are collected.

Since:

  • 5.5.0



164
165
166
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 164

def set_diagnostic_accumulator(diagnostic_accumulator)
  @diagnostic_accumulator = diagnostic_accumulator
end

#startConcurrent::Event

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Starts the data system.

This method will return immediately. The returned event will be set when the system has reached an initial state (either permanently failed, e.g. due to bad auth, or succeeded).

If called multiple times, returns the same event as the first call.

Since:

  • 5.5.0



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 116

def start
  if @disabled
    @logger.warn { "[LDClient] Data system is disabled, SDK will return application-defined default values" }
    @ready_event.set
    return @ready_event
  end

  @stop_event.reset
  @ready_event.reset

  # Start the main coordination thread
  main_thread = Thread.new { run_main_loop }
  main_thread.name = "FDv2-main"
  @threads << main_thread

  @ready_event
end

#stopvoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Halts the data system. Should be called when the client is closed to stop any long running operations. Makes the data system no longer usable.

Since:

  • 5.5.0



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 135

def stop
  @stop_event.set

  @lock.synchronize do
    if @active_synchronizer
      begin
        @active_synchronizer.stop
      rescue => e
        @logger.error { "[LDClient] Error stopping active data source: #{e.message}" }
      end
    end
  end

  # Wait for all threads to complete
  @threads.each do |thread|
    next unless thread.alive?

    thread.join(5.0) # 5 second timeout
    @logger.warn { "[LDClient] Thread #{thread.name} did not terminate in time" } if thread.alive?
  end

  # Close the store
  @store.close

  # Shutdown the shared executor
  @shared_executor.shutdown
end

#storeObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the data store used by the data system.

Since:

  • 5.5.0



169
170
171
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 169

def store
  @store.get_active_store
end

#target_availabilitySymbol

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Indicates the ideal form of data attainable given the current configuration.

Since:

  • 5.5.0



197
198
199
200
201
# File 'lib/ldclient-rb/impl/data_system/fdv2.rb', line 197

def target_availability
  return DataAvailability::REFRESHED if @configured_with_data_sources

  DataAvailability::CACHED
end