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::Interfaces::DataSystem::FetchResult

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. File-based data sources never request the FDv1 Fallback Directive, so the returned FetchResult always reports ‘fallback_to_fdv1: false`.

Parameters:

Returns:

Since:

  • 5.5.0



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
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 80

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

        load_result = load_all_to_changeset
        next load_result unless load_result.success?

        change_set = load_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

  LaunchDarkly::Interfaces::DataSystem::FetchResult.new(result: result, fallback_to_fdv1: false)
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



172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 172

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



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
159
160
161
162
163
164
165
# File 'lib/ldclient-rb/impl/integrations/file_data_source_v2.rb', line 118

def sync(selector_store)
  # First yield initial data
  initial_fetch = fetch(selector_store)
  unless initial_fetch.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_fetch.error,
        Time.now
      )
    )
    return
  end

  yield LaunchDarkly::Interfaces::DataSystem::Update.new(
    state: LaunchDarkly::Interfaces::DataSource::Status::VALID,
    change_set: initial_fetch.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