Skip to content

feat: Add the override layer, the store overlay, and the override source configuration - #222

Draft
kinyoklion wants to merge 1 commit into
rlamb/overrides-java-model-markerfrom
rlamb/overrides-java-override-layer
Draft

kinyoklion wants to merge 1 commit into
rlamb/overrides-java-model-markerfrom
rlamb/overrides-java-override-layer

Conversation

@kinyoklion

Copy link
Copy Markdown
Member

Summary

This adds the override layer that the OVERRIDE specification describes: an override source supplies complete snapshots of flag and segment definitions to an override store, and an overlay at the store read boundary returns the store's entry for a key in preference to LaunchDarkly data. Evaluation, prerequisite and segment resolution, and the all-flags state all read through the overlay, so an override is a full definition that evaluates like any other. Overrides do not take part in the data system: they have no effect on initialization status, data availability, or data source status, and they are never written to a persistent store.

Public surface, all marked experimental and subject to change:

  • DataSystemBuilder.overrides(ComponentConfigurer<OverrideSource>) and DataSystemConfiguration.getOverrideSource(). The option lives on the FDv2 data system builder only. An FDv1 data source configuration has no place to supply one.
  • subsystems.OverrideSource (start with a sink, close) and subsystems.OverrideSink (replace the whole layer with one snapshot). The SDK builds the source like any other component, starts it before the data source so its initial load completes during client construction, and closes it with the client. An offline client starts no override source. A source that cannot be built fails client construction the same way other invalid component configuration does.

Internals:

  • OverrideLayer holds marked shallow copies of the supplied entities in an immutable map that is swapped on each update. The source's objects are never modified.
  • OverrideOverlayStore implements the read boundary: per-key reads prefer the layer, enumeration is the union with override precedence, and when the base store fails while the layer holds entries the layer's entries are still served.
  • OverrideSinkImpl serializes snapshot application and fires the normal flag change notifications for every flag whose merged-view evaluation may have changed, using the dependency tracker over both the old and the new merged views so prerequisite and segment dependents are included.
  • The not-initialized short-circuit consults the layer first: a flag that the layer holds is served before the client has LaunchDarkly data, and any other flag returns the client-not-ready default as before. The all-flags state does the same, logging once that it returned only override entries, and presents an override-affected flag with trackEvents and trackReason false and no debugEventsUntilDate.

The OVERRIDE specification's test vectors run as a unit test through the full client stack (value, variation index, and reason). The per-evaluation summary marker in the vectors is asserted by the events change that follows.

This PR depends on the model and evaluator marking change (rlamb/overrides-java-model-marker) and is based on that branch; retarget it to feat/overrides once that branch merges.

…rce configuration

The OVERRIDE specification defines an override layer: a runtime-mutable
collection of flag and segment definitions, supplied by an override
source as complete snapshots, that takes precedence over LaunchDarkly
data on a per-key basis at the store read boundary. Overrides are not a
data source. They have no effect on initialization status, data
availability, or data source status, and they are never persisted.

Public surface, all experimental and subject to change:
DataSystemBuilder.overrides(ComponentConfigurer<OverrideSource>),
DataSystemConfiguration.getOverrideSource(), and the
subsystems.OverrideSource and subsystems.OverrideSink interfaces. The
SDK builds the source like any other component, starts it before the
data source so its initial load completes during client construction,
and closes it with the client. An offline client starts no override
source. A source that cannot be built fails client construction.

OverrideLayer holds marked shallow copies in an immutable map swapped on
each update. OverrideOverlayStore implements the read boundary with
override precedence for per-key reads and enumeration, and serves the
layer alone when the base store fails. OverrideSinkImpl serializes
snapshot application and fires the normal flag change notifications for
every flag whose merged-view evaluation may have changed.

The not-initialized short-circuit consults the layer first, so a flag
that the layer holds is served before the client has LaunchDarkly data.
The all-flags state does the same and presents an override-affected
flag with event tracking off. The specification's test vectors run as a
unit test through the full client stack.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant