Source code for ldclient.datasystem
"""
Configuration for LaunchDarkly's data acquisition strategy.
"""
from typing import List, Optional
from ldclient.config import DataSourceBuilder, DataSystemConfig
from ldclient.impl.datasourcev2.polling import (
FallbackToFDv1PollingDataSourceBuilder,
PollingDataSourceBuilder
)
from ldclient.impl.datasourcev2.streaming import StreamingDataSourceBuilder
from ldclient.impl.integrations.files.file_data_sourcev2 import (
FileDataSourceV2Builder
)
from ldclient.interfaces import (
DataStoreMode,
FeatureStore,
Initializer,
Synchronizer
)
[docs]
class ConfigBuilder: # pylint: disable=too-few-public-methods
"""
Builder for the data system configuration.
"""
[docs]
def __init__(self) -> None:
self._initializers: Optional[List[DataSourceBuilder[Initializer]]] = None
self._synchronizers: List[DataSourceBuilder[Synchronizer]] = []
self._fdv1_fallback_synchronizer: Optional[DataSourceBuilder[Synchronizer]] = None
self._store_mode: DataStoreMode = DataStoreMode.READ_ONLY
self._data_store: Optional[FeatureStore] = None
[docs]
def initializers(self, initializers: Optional[List[DataSourceBuilder[Initializer]]]) -> "ConfigBuilder":
"""
Sets the initializers for the data system.
"""
self._initializers = initializers
return self
[docs]
def synchronizers(
self,
*sync_builders: DataSourceBuilder[Synchronizer]
) -> "ConfigBuilder":
"""
Sets the synchronizers for the data system.
Accepts one or more synchronizer builders, ordered by preference.
The first synchronizer is the most preferred, with subsequent
synchronizers serving as fallbacks in order of decreasing preference.
Examples:
builder.synchronizers(streaming_builder)
builder.synchronizers(streaming_builder, polling_builder)
builder.synchronizers(sync1, sync2, sync3)
"""
if len(sync_builders) == 0:
raise ValueError("At least one synchronizer must be provided")
self._synchronizers = list(sync_builders)
return self
[docs]
def fdv1_compatible_synchronizer(
self,
fallback: DataSourceBuilder[Synchronizer]
) -> "ConfigBuilder":
"""
Configures the SDK with a fallback synchronizer that is compatible with
the Flag Delivery v1 API.
"""
self._fdv1_fallback_synchronizer = fallback
return self
[docs]
def data_store(self, data_store: FeatureStore, store_mode: DataStoreMode) -> "ConfigBuilder":
"""
Sets the data store configuration for the data system.
"""
self._data_store = data_store
self._store_mode = store_mode
return self
[docs]
def build(self) -> DataSystemConfig:
"""
Builds the data system configuration.
"""
return DataSystemConfig(
initializers=self._initializers,
synchronizers=self._synchronizers if len(self._synchronizers) > 0 else None,
fdv1_fallback_synchronizer=self._fdv1_fallback_synchronizer,
data_store_mode=self._store_mode,
data_store=self._data_store,
)
[docs]
def polling_ds_builder() -> PollingDataSourceBuilder:
"""
Returns a builder for a polling data source.
"""
return PollingDataSourceBuilder()
[docs]
def fdv1_fallback_ds_builder() -> FallbackToFDv1PollingDataSourceBuilder:
"""
Returns a builder for a Flag Delivery v1 compatible fallback polling data source.
"""
return FallbackToFDv1PollingDataSourceBuilder()
[docs]
def streaming_ds_builder() -> StreamingDataSourceBuilder:
"""
Returns a builder for a streaming data source.
"""
return StreamingDataSourceBuilder()
[docs]
def file_ds_builder(paths: List[str]) -> FileDataSourceV2Builder:
"""
Returns a builder for a file-based data source.
"""
return FileDataSourceV2Builder(paths)
[docs]
def default() -> ConfigBuilder:
"""
Default is LaunchDarkly's recommended flag data acquisition strategy.
Currently, it operates a two-phase method for obtaining data: first, it
requests data from LaunchDarkly's global CDN. Then, it initiates a
streaming connection to LaunchDarkly's Flag Delivery services to
receive real-time updates.
If the streaming connection is interrupted for an extended period of
time, the SDK will automatically fall back to polling the global CDN
for updates.
"""
polling_builder = polling_ds_builder()
streaming_builder = streaming_ds_builder()
fallback = fdv1_fallback_ds_builder()
builder = ConfigBuilder()
builder.initializers([polling_builder])
builder.synchronizers(streaming_builder, polling_builder)
builder.fdv1_compatible_synchronizer(fallback)
return builder
[docs]
def streaming() -> ConfigBuilder:
"""
Streaming configures the SDK to efficiently streams flag/segment data
in the background, allowing evaluations to operate on the latest data
with no additional latency.
"""
streaming_builder = streaming_ds_builder()
fallback = fdv1_fallback_ds_builder()
builder = ConfigBuilder()
builder.synchronizers(streaming_builder)
builder.fdv1_compatible_synchronizer(fallback)
return builder
[docs]
def polling() -> ConfigBuilder:
"""
Polling configures the SDK to regularly poll an endpoint for
flag/segment data in the background. This is less efficient than
streaming, but may be necessary in some network environments.
"""
polling_builder: DataSourceBuilder[Synchronizer] = polling_ds_builder()
fallback = fdv1_fallback_ds_builder()
builder = ConfigBuilder()
builder.synchronizers(polling_builder)
builder.fdv1_compatible_synchronizer(fallback)
return builder
[docs]
def custom() -> ConfigBuilder:
"""
Custom returns a builder suitable for creating a custom data
acquisition strategy. You may configure how the SDK uses a Persistent
Store, how the SDK obtains an initial set of data, and how the SDK
keeps data up-to-date.
"""
return ConfigBuilder()
[docs]
def daemon(store: FeatureStore) -> ConfigBuilder:
"""
Daemon configures the SDK to read from a persistent store integration
that is populated by Relay Proxy or other SDKs. The SDK will not connect
to LaunchDarkly. In this mode, the SDK never writes to the data store.
"""
return custom().data_store(store, DataStoreMode.READ_ONLY)
[docs]
def persistent_store(store: FeatureStore) -> ConfigBuilder:
"""
PersistentStore is similar to Default, with the addition of a persistent
store integration. Before data has arrived from LaunchDarkly, the SDK is
able to evaluate flags using data from the persistent store. Once fresh
data is available, the SDK will no longer read from the persistent store,
although it will keep it up-to-date.
"""
return default().data_store(store, DataStoreMode.READ_WRITE)