Module: LaunchDarkly::Impl::DataSystem Private
- Defined in:
- lib/ldclient-rb/impl/data_system.rb,
lib/ldclient-rb/impl/data_system/fdv1.rb,
lib/ldclient-rb/impl/data_system/fdv2.rb,
lib/ldclient-rb/impl/data_system/polling.rb,
lib/ldclient-rb/impl/data_system/streaming.rb,
lib/ldclient-rb/impl/data_system/protocolv2.rb,
lib/ldclient-rb/impl/data_system/http_config_options.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Mixin that defines the required methods of a data system implementation. The data system is responsible for managing the SDK’s data model, including storage, retrieval, and change detection for feature flag configurations.
This module also contains supporting classes and additional mixins for data system implementations, such as DataAvailability, Update, and protocol-specific mixins.
For operations that can fail, use Result from util.rb.
Application code should not need to implement this directly; it is used internally by the SDK’s data system implementations.
Defined Under Namespace
Modules: DiagnosticAccumulator, DiagnosticSource, Initializer, ProtocolV2, SyncResult, Synchronizer Classes: DataAvailability, FDv1, FDv2, HTTPFDv1PollingRequester, HTTPPollingRequester, HttpConfigOptions, PollingDataSource, StreamingDataSource, Update
Constant Summary collapse
- FDV2_POLLING_ENDPOINT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"/sdk/poll"- FDV1_POLLING_ENDPOINT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"/sdk/latest-all"- LD_ENVID_HEADER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"X-LD-EnvID"- LD_FD_FALLBACK_HEADER =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"X-LD-FD-Fallback"- FDV2_STREAMING_ENDPOINT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
"/sdk/stream"- STREAM_READ_TIMEOUT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Allows for up to 5 minutes to elapse without any data sent across the stream. The heartbeats sent as comments on the stream will keep this from triggering.
5 * 60
Class Method Summary collapse
-
.fdv1_fallback_requested?(headers) ⇒ Boolean
private
Reports whether the response headers signal that the SDK should fall back to the FDv1 protocol.
-
.fdv1_polling_payload_to_changeset(data) ⇒ LaunchDarkly::Result<LaunchDarkly::Interfaces::DataSystem::ChangeSet, String>
private
Converts an FDv1 polling payload into a ChangeSet.
-
.lookup_header(headers, name) ⇒ String, ...
private
Performs a case-insensitive header lookup that works with both case-insensitive header containers (e.g. ‘HTTP::Headers`) and plain Ruby hashes – including hashes whose keys we have downcased ourselves before reaching this code path.
-
.polling_payload_to_changeset(data) ⇒ LaunchDarkly::Result<LaunchDarkly::Interfaces::DataSystem::ChangeSet, String>
private
Converts a polling payload into a ChangeSet.
Instance Method Summary collapse
-
#data_availability ⇒ Symbol
private
Indicates what form of data is currently available.
-
#data_source_status_provider ⇒ LaunchDarkly::Interfaces::DataSource::StatusProvider
private
Returns an interface for tracking the status of the data source.
-
#data_store_status_provider ⇒ LaunchDarkly::Interfaces::DataStore::StatusProvider
private
Returns an interface for tracking the status of a persistent data store.
-
#flag_change_broadcaster ⇒ LaunchDarkly::Impl::Broadcaster
private
Returns the broadcaster for flag change notifications.
-
#set_diagnostic_accumulator(diagnostic_accumulator) ⇒ void
private
Sets the diagnostic accumulator for streaming initialization metrics.
-
#start ⇒ Concurrent::Event
private
Starts the data system.
-
#stop ⇒ void
private
Halts the data system.
-
#store ⇒ Object
private
Returns the data store used by the data system.
-
#target_availability ⇒ Symbol
private
Indicates the ideal form of data attainable given the current configuration.
Class Method Details
.fdv1_fallback_requested?(headers) ⇒ Boolean
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.
Reports whether the response headers signal that the SDK should fall back to the FDv1 protocol. Lookup is case-insensitive so callers do not need to know whether the header map preserves canonical casing (e.g. HTTP::Headers) or has been normalized to lowercase (e.g. LaunchDarkly::Impl::DataSystem::HTTPPollingRequester#fetch).
34 35 36 37 38 39 40 |
# File 'lib/ldclient-rb/impl/data_system/polling.rb', line 34 def self.fdv1_fallback_requested?(headers) return false if headers.nil? value = lookup_header(headers, LD_FD_FALLBACK_HEADER) # http gem returns arrays for repeated headers; normalize to a string. value = value.first if value.is_a?(Array) value == 'true' end |
.fdv1_polling_payload_to_changeset(data) ⇒ LaunchDarkly::Result<LaunchDarkly::Interfaces::DataSystem::ChangeSet, String>
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.
Converts an FDv1 polling payload into a ChangeSet.
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/ldclient-rb/impl/data_system/polling.rb', line 537 def self.fdv1_polling_payload_to_changeset(data) builder = LaunchDarkly::Interfaces::DataSystem::ChangeSetBuilder.new builder.start(LaunchDarkly::Interfaces::DataSystem::IntentCode::TRANSFER_FULL) selector = LaunchDarkly::Interfaces::DataSystem::Selector.no_selector kind_mappings = [ [LaunchDarkly::Interfaces::DataSystem::ObjectKind::FLAG, :flags], [LaunchDarkly::Interfaces::DataSystem::ObjectKind::SEGMENT, :segments], ] kind_mappings.each do |kind, fdv1_key| kind_data = data[fdv1_key] next if kind_data.nil? unless kind_data.is_a?(Hash) return LaunchDarkly::Result.fail("Invalid format: #{fdv1_key} is not an object") end kind_data.each do |key, flag_or_segment| unless flag_or_segment.is_a?(Hash) return LaunchDarkly::Result.fail("Invalid format: #{key} is not an object") end version = flag_or_segment[:version] return LaunchDarkly::Result.fail("Invalid format: #{key} does not have a version set") if version.nil? builder.add_put(kind, key, version, flag_or_segment) end end LaunchDarkly::Result.success(builder.finish(selector)) end |
.lookup_header(headers, name) ⇒ String, ...
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.
Performs a case-insensitive header lookup that works with both case-insensitive header containers (e.g. ‘HTTP::Headers`) and plain Ruby hashes – including hashes whose keys we have downcased ourselves before reaching this code path.
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 |
# File 'lib/ldclient-rb/impl/data_system/polling.rb', line 52 def self.lookup_header(headers, name) return nil if headers.nil? if headers.is_a?(Hash) # Plain hash: try canonical case, then exact lowercase, then a # case-insensitive scan as a final fallback. value = headers[name] return value unless value.nil? downcased = name.downcase value = headers[downcased] return value unless value.nil? headers.each_pair do |key, val| return val if key.to_s.downcase == downcased end return nil end # Non-hash container (e.g. HTTP::Headers). Lookup via [] is # already case-insensitive on those types. return headers[name] if headers.respond_to?(:[]) nil end |
.polling_payload_to_changeset(data) ⇒ LaunchDarkly::Result<LaunchDarkly::Interfaces::DataSystem::ChangeSet, String>
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.
Converts a polling payload into a ChangeSet.
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
# File 'lib/ldclient-rb/impl/data_system/polling.rb', line 471 def self.polling_payload_to_changeset(data) unless data[:events].is_a?(Array) return LaunchDarkly::Result.fail("Invalid payload: 'events' key is missing or not a list") end builder = LaunchDarkly::Interfaces::DataSystem::ChangeSetBuilder.new data[:events].each do |event| unless event.is_a?(Hash) return LaunchDarkly::Result.fail("Invalid payload: 'events' must be a list of objects") end next unless event[:event] case event[:event].to_sym when LaunchDarkly::Interfaces::DataSystem::EventName::SERVER_INTENT begin server_intent = LaunchDarkly::Interfaces::DataSystem::ServerIntent.from_h(event[:data]) rescue ArgumentError => e return LaunchDarkly::Result.fail("Invalid JSON in server intent", e) end if server_intent.payload.code == LaunchDarkly::Interfaces::DataSystem::IntentCode::TRANSFER_NONE return LaunchDarkly::Result.success(LaunchDarkly::Interfaces::DataSystem::ChangeSetBuilder.no_changes) end builder.start(server_intent.payload.code) when LaunchDarkly::Interfaces::DataSystem::EventName::PUT_OBJECT begin put = LaunchDarkly::Impl::DataSystem::ProtocolV2::PutObject.from_h(event[:data]) rescue ArgumentError => e return LaunchDarkly::Result.fail("Invalid JSON in put object", e) end builder.add_put(put.kind, put.key, put.version, put.object) when LaunchDarkly::Interfaces::DataSystem::EventName::DELETE_OBJECT begin delete_object = LaunchDarkly::Impl::DataSystem::ProtocolV2::DeleteObject.from_h(event[:data]) rescue ArgumentError => e return LaunchDarkly::Result.fail("Invalid JSON in delete object", e) end builder.add_delete(delete_object.kind, delete_object.key, delete_object.version) when LaunchDarkly::Interfaces::DataSystem::EventName::PAYLOAD_TRANSFERRED begin selector = LaunchDarkly::Interfaces::DataSystem::Selector.from_h(event[:data]) changeset = builder.finish(selector) return LaunchDarkly::Result.success(changeset) rescue ArgumentError, RuntimeError => e return LaunchDarkly::Result.fail("Invalid JSON in payload transferred object", e) end end end LaunchDarkly::Result.fail("didn't receive any known protocol events in polling payload") end |
Instance Method Details
#data_availability ⇒ Symbol
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.
89 90 91 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 89 def data_availability raise NotImplementedError, "#{self.class} must implement #data_availability" end |
#data_source_status_provider ⇒ LaunchDarkly::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.
51 52 53 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 51 def data_source_status_provider raise NotImplementedError, "#{self.class} must implement #data_source_status_provider" end |
#data_store_status_provider ⇒ LaunchDarkly::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.
66 67 68 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 66 def data_store_status_provider raise NotImplementedError, "#{self.class} must implement #data_store_status_provider" end |
#flag_change_broadcaster ⇒ LaunchDarkly::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.
78 79 80 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 78 def flag_change_broadcaster raise NotImplementedError, "#{self.class} must implement #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.
118 119 120 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 118 def set_diagnostic_accumulator(diagnostic_accumulator) raise NotImplementedError, "#{self.class} must implement #set_diagnostic_accumulator" end |
#start ⇒ Concurrent::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.
29 30 31 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 29 def start raise NotImplementedError, "#{self.class} must implement #start" end |
#stop ⇒ 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.
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.
39 40 41 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 39 def stop raise NotImplementedError, "#{self.class} must implement #stop" end |
#store ⇒ Object
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.
107 108 109 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 107 def store raise NotImplementedError, "#{self.class} must implement #store" end |
#target_availability ⇒ Symbol
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.
98 99 100 |
# File 'lib/ldclient-rb/impl/data_system.rb', line 98 def target_availability raise NotImplementedError, "#{self.class} must implement #target_availability" end |