-
Notifications
You must be signed in to change notification settings - Fork 3
feat(js): add sticky assignment support with remote resolver fallback #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Implements sticky resolve functionality to ensure consistent variant assignments even when user context changes or new assignments are paused. Key changes: - Add proto definitions for ResolveWithStickyRequest/Response - Add StickyResolveStrategy interface with MaterializationRepository and ResolverFallback implementations - Refactor evaluate() to always use sticky resolve via resolveWithStickyInternal() - Add materialization utility functions for loading/storing assignments - Make evaluate() async to support async storage operations - Add comprehensive test coverage (25 tests) The implementation matches the Java SDK pattern, with fire-and-forget storage updates and recursive retry logic for missing materializations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Implements RemoteResolverFallback which delegates to the remote Confidence API when materializations are missing. This is now the default strategy, simplifying setup for users while maintaining extensibility. Changes: - Add RemoteResolverFallback class with remote API resolution - Default stickyResolveStrategy to RemoteResolverFallback - Remove non-null assertions for stickyResolveStrategy - Export RemoteResolverFallback in public API - Add comprehensive tests (16 tests, all passing) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…ation Refactor FileBackedMaterializationRepo to use InMemoryMaterializationRepo as backing store, reading from file only on init and writing only on close. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove resolveFlags method from LocalResolver interface and WasmResolver implementation. Update all tests to use resolveWithSticky instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove ResolverFallback interface from exports as users should use the concrete RemoteResolverFallback implementation instead. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Remove ResolveFlagsRequest and ResolveFlagsResponse type exports as they are only used internally by ResolverFallback which is no longer public. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Change `stickyResolveStrategy` to `materializationRepository` parameter accepting either MaterializationRepository or RemoteResolverFallback. Remove StickyResolveStrategy from public exports. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Simplify API by removing intermediate interfaces: - Remove StickyResolveStrategy base interface - Remove ResolverFallback interface and type guards - Make MaterializationRepository standalone with close() method - Rename StickyResolveStrategy.ts to MaterializationRepository.ts - Update ConfidenceServerProviderLocal to use optional MaterializationRepository - RemoteResolverFallback is now created internally when no repository provided 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
openfeature-provider/js/examples/FileBackedMaterializationRepo.ts
Outdated
Show resolved
Hide resolved
* @returns Map of materialization ID to MaterializationInfo for this unit | ||
*/ | ||
loadMaterializedAssignmentsForUnit( | ||
unit: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to load for multiple units?
* @param assignments - Map of materialization ID to MaterializationInfo | ||
*/ | ||
storeAssignment( | ||
unit: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, should be possible to store multiple units?
* } | ||
* ``` | ||
*/ | ||
export interface MaterializationRepository { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should think a bit about this interface. Is it only us who should implement it? Do we need it to specify the full model of data? Could it for instance be a simple KV store with bytebuffer values? Probably not, since we actually update the values rather than overwriting them. It could be a flattened key space though like type Record = [key:[unit:string, materialization:string, rule:string], variant:string]
. Don't feel confident we should use the PB generated types in the interface anyhow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, do we expect the implementation to be super low latency and we can afford to load materializations one by one, or does it need to support loading in bulk?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an API proposal:
type Variant = string;
type MaterializationInfo = {
[unit:string]: {
[materialization:string]: {
[rule:string]: Variant
}
}
}
type RuleList = string[]
type MaterializationQuery = {
[unit:string]: {
[materialization:string]: RuleList
}
}
interface MaterializationRepository {
loadMaterializations(query:MaterializationQuery):Promise<MaterializationInfo>
storeMaterializations(materializations:MaterializationInfo):Promise<void>
}
Remove MaterializationRepository from public API for now: - Removed materializationRepository option from ProviderOptions - Updated provider to always use remote resolver fallback for sticky assignments - Materializations stored on Confidence servers with 90-day TTL - Marked MaterializationRepository interface and utilities as WIP Documentation updates: - Updated README to explain remote fallback approach - Added note about upcoming custom storage feature - Marked MAT_REPO_EXAMPLES.md as work in progress - Updated tests to reflect remote fallback behavior The MaterializationRepository feature will be added in a future release to allow users to connect their own storage (Redis, database, etc.). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Summary
Adds sticky assignment support to the JavaScript OpenFeature provider using remote resolver fallback.
How it works
Key changes
ResolveWithStickyRequest
support in providerFuture work
Custom
MaterializationRepository
support is planned for a future release to allow users to provide their own storage backend (Redis, database, file system, etc.). The interface and utilities are already in place but marked as WIP.🤖 Generated with Claude Code