-
Notifications
You must be signed in to change notification settings - Fork 46
feat: Add multi-provider support #1500
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?
feat: Add multi-provider support #1500
Conversation
Signed-off-by: suvaidkhan <[email protected]>
8710a52
to
f07dd25
Compare
|
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.
Looks good so far!
I'm not sure if we want to add a json dependecy (which might also produce the License Compliance error) "just" so that we can build up the metadata name string.
private String metadataName; | ||
|
||
/** | ||
* Constructs a MultiProvider with the given list of FeatureProviders, using a default strategy. |
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.
I think the comment should say what the default strategy is
json.put("name", NAME); | ||
JSONObject providersMetadata = new JSONObject(); | ||
json.put("originalMetadata", providersMetadata); | ||
ExecutorService initPool = Executors.newFixedThreadPool(INIT_THREADS_COUNT); |
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.
ExecutorService initPool = Executors.newFixedThreadPool(INIT_THREADS_COUNT); | |
ExecutorService initPool = Executors.newFixedThreadPool(Math.min(INIT_THREADS_COUNT, providers.size())); |
throw new GeneralError("init failed"); | ||
} | ||
} | ||
metadataName = json.toString(); |
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.
If the executer service is unused from this point onwards, we should shut it down
assertThrows(FlagNotFoundError.class, () -> finalMultiProvider1.getStringEvaluation("non-existing", "", null)); | ||
|
||
multiProvider.shutdown(); | ||
multiProvider = new MultiProvider(providers, new FirstSuccessfulStrategy()); |
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.
There should probably be a test file with tests for each strategy. If you want to reduce code duplication by the flag setup, make those test classes extend some common test setup class
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1500 +/- ##
============================================
+ Coverage 92.97% 93.63% +0.65%
- Complexity 488 519 +31
============================================
Files 46 49 +3
Lines 1182 1257 +75
Branches 103 112 +9
============================================
+ Hits 1099 1177 +78
+ Misses 53 49 -4
- Partials 30 31 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Should I construct the json using Strings? |
Maybe it would be worth it. |
@chrfwow @toddbaert any updates on this? |
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.
Thank you, great effort. I am looking forward to having the multiprovider migrated. For me, the added dependency is currently a show stopper, because I think we can handle that with proper and simple data classes, even with better metadata support overall (not losing information from the sub providers). I added simple but untested code snippets to my review. Please let me know what you think about this approach.
public static final int INIT_THREADS_COUNT = 8; | ||
private final Map<String, FeatureProvider> providers; | ||
private final Strategy strategy; | ||
private String metadataName; |
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.
[suggestion] as this variable is more than just a name - it is a json object, we might want to rename it to something more representing like
private String metadataName; | |
private String metadata; |
*/ | ||
@Override | ||
public void initialize(EvaluationContext evaluationContext) throws Exception { | ||
JSONObject json = new JSONObject(); |
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.
[nit] If this is really the only reason why we add a JSON dependency, can we maybe utilize our own object representation of metadata?
something like
@Override
public void initialize(EvaluationContext evaluationContext) throws Exception {
var metadataBuilder = MultiProviderMetadata.builder();
metadataBuilder.name(NAME);
Map<String, Metadata> providersMetadata = new HashMap();
ExecutorService initPool = Executors.newFixedThreadPool(INIT_THREADS_COUNT);
Collection<Callable<Boolean>> tasks = new ArrayList<>(providers.size());
for (FeatureProvider provider : providers.values()) {
tasks.add(() -> {
provider.initialize(evaluationContext);
return true;
});
Metadata providerMetadata = provider.getMetadata();
providersMetadata.put(providerMetadata.getName(), providerMetadata);
}
metadataBuilder.originalMetadata(providersMetadata);
List<Future<Boolean>> results = initPool.invokeAll(tasks);
for (Future<Boolean> result : results) {
if (!result.get()) {
throw new GeneralError("init failed");
}
}
metadata = metadataBuilder.build();
}
with an own implementation of the metadata interface called MultiProviderMetadata
@Data
@Builder
public class MultiProviderMetadata implements Metadata {
String name;
Map<String, Metadata> originalMetadata;
}
wdyt? This would eliminate the dependency and make editing the code easier - I did not test this, and I am not sure if we will miss information with JSON conversion, etc.
This PR
Related Issues
Resolves #1486
Follow-up Tasks
Multiprovider should be removed from the contrib codebase