[Multi-provider] Gaps identified relative to js-sdk reference implementation

Open
#1,882 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Stale
Tech stack
java

Research direction

Start by locating the Java MultiProvider, FirstMatchStrategy, and FirstSuccessfulStrategy implementations and compare them with the referenced js-sdk and other SDK implementations. Work through the five gaps separately, beginning with event aggregation and hook execution. Done means child events, hooks, tracking, comparison behavior, and duplicate-name handling match the stated expectations without losing providers.

Written by the indexing model from the issue text.

Description

multi-provider

Context

We conducted a cross-SDK comparison of all MultiProvider implementations using the js-sdk as the reference. The Java MultiProvider was recently moved into the core SDK in #1765, and while functional for basic use cases, we identified several gaps relative to the reference implementation. Some of these were already noted during the original PR review.

Gaps

1. Child provider event aggregation and status tracking (High)

The MultiProvider extends EventProvider but does not listen to or forward events from child providers. If a child provider emits PROVIDER_ERROR, PROVIDER_STALE, or PROVIDER_CONFIGURATION_CHANGED at runtime, those events are not surfaced. This was called out in the #1765 review by @guidobrei:

"we effectively lose the Event features when using MultiProvider"

Expected behavior:

  • Listen to each child provider's events
  • Maintain a per-provider status map
  • Compute an aggregate status using "worst-wins" precedence: FATAL > NOT_READY > ERROR > STALE > READY
  • Emit the corresponding event when the aggregate status changes
  • Always forward PROVIDER_CONFIGURATION_CHANGED events (pass-through)

Reference: js-sdk status-tracker.ts, dotnet-sdk HandleProviderEventAsync / DetermineAggregateStatus

2. Per-provider hook execution during evaluation (High)

The strategy calls provider evaluation methods directly (e.g. provider.getBooleanEvaluation(...)), bypassing the SDK's hook pipeline. If a child provider defines hooks via getProviderHooks(), those hooks are not executed.

Expected behavior:

  • Before evaluating a child provider, run its before hooks with an isolated copy of the hook context
  • On success: run after hooks
  • On error: run error hooks
  • Always: run finally hooks
  • Hook context must be isolated per-provider to prevent cross-provider mutation

Reference: js-sdk hook-executor.ts, go-sdk isolation.go, dotnet-sdk ProviderExtensions.EvaluateAsync

3. Tracking event forwarding (High)

track() is not overridden. The default no-op implementation means tracking events are not forwarded to child providers.

Expected behavior:

  • Iterate over child providers and forward track() calls
  • The strategy should control which providers receive tracking (e.g. skip NOT_READY / FATAL providers)
  • Errors from individual track() calls should be caught and logged, not propagated

Reference: js-sdk multi-provider.ts track(), dotnet-sdk MultiProvider.cs Track()

4. ComparisonStrategy (Medium)

Only FirstMatchStrategy and FirstSuccessfulStrategy exist. There is no ComparisonStrategy for evaluating all providers and comparing results (useful for migration validation and consistency checks).

Expected behavior:

  • Evaluate all providers (ideally in parallel)
  • If all providers agree on the value, return it
  • If providers disagree, call an optional onMismatch callback and return the designated fallback provider's result
  • If any provider errors, collect and report all errors
  • Constructor accepts a fallbackProvider and optional onMismatch callback

Reference: js-sdk comparison-strategy.ts, go-sdk comparison_strategy.go, dotnet-sdk ComparisonStrategy.cs

5. Duplicate provider name handling (Medium)

When two child providers share the same metadata.name, the later provider silently overwrites the earlier one in the internal LinkedHashMap. The first provider is effectively lost. Related to #1792.

Expected behavior:

  • If an explicit name conflicts with an existing name, throw (misconfiguration)
  • If multiple providers share the same metadata-derived name, auto-deduplicate with a numeric suffix (name-1, name-2, etc.)
  • All providers should be preserved

Reference: js-sdk registerProviders(), dotnet-sdk RegisterProviders()

Spec Reference

https://openfeature.dev/specification/appendix-a/#multi-provider

Dominant language
Java
Stars
128
Forks
61
Avg merge
5h 57m
Merged PRs (30d)
26

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from open-feature/java-sdk

All issues in open-feature/java-sdk

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.