Repository navigation
FeatureManager isEnabledAsync method does not allow to pass extra parameters to compare in custom Feature Filters using Reactive Programming #29691
Description
Question/Help/Comment/Advice
Context
When we are using reactive programming the method isEnabledAsync from FeatureManager class in App Configuration package allows getting a Mono, which helps with Reactive programming execution. However, if we have a Custom Feature Filter which requires us to compare/evaluate against a value that we desire to pass, it turns out complicated, because the current solution to pass that value needs to be wired in the feature filter component, but in a race condition that value can change since it was not passed by parameters to the method evaluate to apply the logic. example below:
RestController
@Autowired
private FeatureManager featureManager;
@Autowired
private CreditCardFilter filter;
@PostMapping(value = "/getFeature", produces = {MediaType.APPLICATION_JSON_VALUE},consumes = {MediaType.APPLICATION_JSON_VALUE})
public Mono<HashMap<String,Object>> getFeatureStatus(@RequestBody HashMap<String,Object> request){
Function<Boolean,HashMap<String,Object>> createResponse = enabled -> new HashMap<String, Object>(){{
put("ResponseCode",0);
put("IsEnabled",enabled);
}};
/**
How to pass the credit card value to review in Reactive programming if:
1.- The current thread is going to set the credit card value in the Component that uses FeatureFilter
2.- Once the return featureManager.isEnabledAsync is executed, this is going to release the current thread
to allow another incoming request
3.- Another incoming request arrives and set a new value in the Component for FeatureFilter
4.- During the execution of the first thread in some moment in the chain is going to invoke the FeatureFilter Component,
but that value could be changed in the second request made.
**/
CreditCardParametersFilter creditCard = new CreditCardParametersFilter();
creditCard.setCreditCard((String)request.get("creditCard"));
filter.setCreditCard(creditCard);
return featureManager.isEnabledAsync("CreditCardFeatureFlag")
.doOnSuccess(enabled -> {
//apply any logic
System.out.println("AnotherFeature -->" + enabled);
}).map(createResponse);
}
FeatureFilter Component
@Component("Filter.CreditCard")
public class CreditCardFilter implements FeatureFilter {
private CreditCardParametersFilter creditCard;
public void setCreditCard(CreditCardParametersFilter creditCard) {
this.creditCard = creditCard;
}
@Override
public boolean evaluate(FeatureFilterEvaluationContext featureFilterEvaluationContext) {
String binCard = (String)featureFilterEvaluationContext.getParameters().get("BIN");
String binNumberRequest = creditCard.getBINCard();
return binCard.equals(binNumberRequest);
}
}
How do we handle this kind of scenario, to avoid problems when we are using reactive programming and we need to pass a parameter to FeatureFilter?
I tried a possible ugly solution where I extended the FeatureManager in another component and I rewrite the method isEnabledAsync and subsequent private methods to pass the parameter, as well as using reflection to access parent private members.
Any Advice, Help, or available solution?
Regards
Activity
mrm9084 commentedon Jun 30, 2022
HI, gaderGarcia, If you updated your feature filter to be in the request scope you can then access the request through an
HttpServletRequest.This should work.
It looks like some documentation should be update for the scenario. This is similar to how our
TargetingFilteris implemented.gaderGarcia commentedon Jun 30, 2022
Hi Matthew Metcalf (@mrm9084) thanks for the reply. Yes, that was one of the approaches that I used when I'm not using reactive programming and it works perfectly because the current thread is blocking until complete the whole execution.
However, if we use reactive programming, we can set the HttpServletRequest a value in a controller, but once we release or execute the isEnabledAsync method without using the block() this will release the current thread, allowing us to accept another incoming request that could change the value that we already set. Also, If I'm not wrong HttpServletRequest is not allowed in Reactive Spring/WebFlux.
Maybe I'm wrong in my use case, but the philosophy of reactive/functional programming is to use the in parameters passed to method/function to produce the out result without affecting or updating a state that in transition/execution can be changed.
gaderGarcia commentedon Jul 8, 2022
Any update on this? or the current Feature Flags dependencies for Spring is just for Spring boot MVC and it is not considered for reactive programming using webflux and netty
mrm9084 commentedon Jul 8, 2022
gaderGarcia The main use for this right now is Spring Boot MVC. It should work, not sure what exactly is going wrong. It might be fixed in a beta release we have out.
The beta is for a new our new Dynamic Features work, but it did fix a few things in the original release.
github-actions commentedon Jun 28, 2024
Hi gaderGarcia, we deeply appreciate your input into this project. Regrettably, this issue has remained unresolved for over 2 years and inactive for 30 days, leading us to the decision to close it. We've implemented this policy to maintain the relevance of our issue queue and facilitate easier navigation for new contributors. If you still believe this topic requires attention, please feel free to create a new issue, referencing this one. Thank you for your understanding and ongoing support.
mrm9084 commentedon Oct 10, 2025
We recently released version 6 which should fix this issue: https://learn.microsoft.com/en-us/azure/azure-app-configuration/howto-convert-to-the-new-spring-boot. If this is still an issue please create a new issue. Thanks.