Class: LaunchDarkly::Impl::Integrations::FileDataSourceV2 Private

Inherits:
Object
  • Object
show all
Includes:
LaunchDarkly::Interfaces::DataSystem::Initializer, LaunchDarkly::Interfaces::DataSystem::Synchronizer
Defined in:
lib/ldclient-rb/impl/integrations/file_data_source_v2.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.

Internal implementation of both Initializer and Synchronizer protocols for file-based data.

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:

  • As an Initializer: reads files once and returns initial data
  • As a Synchronizer: watches for file changes and yields updates

The files use the same format as the v1 file data source, supporting flags, flagValues, and segments in JSON or YAML format.

Since:

  • 5.5.0

Constant Summary collapse

@@have_listen =

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

To avoid pulling in 'listen' and its transitive dependencies for people who aren't using the file data source or who don't need auto-updating, we only enable auto-update if the 'listen' gem has been provided by the host app.

Since:

  • 5.5.0

false

Instance Method Summary collapse

Constructor Details

#initialize(logger, paths:, poll_interval: 1) ⇒ FileDataSourceV2

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 the file data source.

Parameters:

  • logger (Logger)

    the logger

  • paths (Array<String>, String)

    file paths to load (or a single path string)

  • poll_interval (Float) (defaults to: 1)

    seconds between polling checks when watching files (default: 1)

Since:

  • 5.5.0



50
51
52
53
54
55
56
57
58
59
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 50

def initialize(logger, paths:, poll_interval: 1)
  @logger = logger
  @paths = paths.is_a?(Array) ? paths : [paths]
  @poll_interval = poll_interval

  @closed = false
  @update_queue = Queue.new
  @lock = Mutex.new
  @listener = nil
end

Instance Method Details

#fetch(selector_store) ⇒ LaunchDarkly::Result

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.

Implementation of the Initializer.fetch method.

Reads all configured files once and returns their contents as a Basis.

Parameters:

Returns:

Since:

  • 5.5.0



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 78

def fetch(selector_store)
  @lock.synchronize do
    if @closed
      return LaunchDarkly::Result.fail('FileDataV2 source has been closed')
    end

    result = load_all_to_changeset
    return result unless result.success?

    change_set = result.value
    basis = LaunchDarkly::Interfaces::DataSystem::Basis.new(
      change_set: change_set,
      persist: false,
      environment_id: nil
    )

    LaunchDarkly::Result.success(basis)
  end
rescue => e
  @logger.error { "[LDClient] Error fetching file data: #{e.message}" }
  LaunchDarkly::Result.fail("Error fetching file data: #{e.message}", e)
end

#nameString

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.

Return the name of this data source.

Returns:

  • (String)

Since:

  • 5.5.0



66
67
68
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 66

def name
  'FileDataV2'
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.

Stop the data source and clean up resources.

Since:

  • 5.5.0



165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 165

def stop
  @lock.synchronize do
    return if @closed
    @closed = true

    listener = @listener
    @listener = nil

    listener&.stop
  end

  # Signal shutdown to sync generator
  @update_queue.push(nil)
end

#sync(selector_store) {|LaunchDarkly::Interfaces::DataSystem::Update| ... } ⇒ 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.

Implementation of the Synchronizer.sync method.

Yields initial data from files, then continues to watch for file changes and yields updates when files are modified.

Parameters:

Yields:

Since:

  • 5.5.0



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 111

def sync(selector_store)
  # First yield initial data
  initial_result = fetch(selector_store)
  unless initial_result.success?
    yield LaunchDarkly::Interfaces::DataSystem::Update.new(
      state: LaunchDarkly::Interfaces::DataSource::Status::OFF,
      error: LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
        LaunchDarkly::Interfaces::DataSource::ErrorInfo::INVALID_DATA,
        0,
        initial_result.error,
        Time.now
      )
    )
    return
  end

  yield LaunchDarkly::Interfaces::DataSystem::Update.new(
    state: LaunchDarkly::Interfaces::DataSource::Status::VALID,
    change_set: initial_result.value.change_set
  )

  # Start watching for file changes
  @lock.synchronize do
    @listener = start_listener unless @closed
  end

  until @closed
    begin
      update = @update_queue.pop

      # stop() pushes nil to wake us up when shutting down
      break if update.nil?

      yield update
    rescue => e
      yield LaunchDarkly::Interfaces::DataSystem::Update.new(
        state: LaunchDarkly::Interfaces::DataSource::Status::OFF,
        error: LaunchDarkly::Interfaces::DataSource::ErrorInfo.new(
          LaunchDarkly::Interfaces::DataSource::ErrorInfo::UNKNOWN,
          0,
          "Error in file data synchronizer: #{e.message}",
          Time.now
        )
      )
      break
    end
  end
end