Context
The local resolver providers use a compositional pattern: WasmResolver → RecoveringResolver → PooledResolver. Materialization suspend/resume logic currently lives in the provider/caller layer across all implementations (Go, Java).
Suggestion
Add a MaterializingResolver as a composable layer in the resolver stack, wrapping the pooled resolver and a MaterializationStore:
WasmResolver → RecoveringResolver → PooledResolver → MaterializingResolver
This would apply to all providers that use the compositional pattern.
Benefits
- Single responsibility — each layer does exactly one thing; the provider focuses on OpenFeature lifecycle (init, shutdown, scheduling)
- Testability — materialization suspend/resume can be tested in isolation without standing up the full provider
- Reusability — the resolver stack becomes self-contained and usable outside the provider (e.g. proxy services like
FlagResolverService)
- Consistency — materialization handling is defined once per language rather than duplicated across different callers
Trade-offs
- Adds one more layer to the composition chain
- The
LocalResolver interface stays materialization-unaware — the MaterializingResolver handles ResolveProcessResponse suspend/resume internally and exposes a simpler resolve contract to callers
Context
The local resolver providers use a compositional pattern:
WasmResolver → RecoveringResolver → PooledResolver. Materialization suspend/resume logic currently lives in the provider/caller layer across all implementations (Go, Java).Suggestion
Add a
MaterializingResolveras a composable layer in the resolver stack, wrapping the pooled resolver and aMaterializationStore:This would apply to all providers that use the compositional pattern.
Benefits
FlagResolverService)Trade-offs
LocalResolverinterface stays materialization-unaware — theMaterializingResolverhandlesResolveProcessResponsesuspend/resume internally and exposes a simpler resolve contract to callers