Skip to content

FeatureManager isEnabledAsync method does not allow to pass extra parameters to compare in custom Feature Filters using Reactive Programming #29691

Closed as not planned

Description

@gaderGarcia

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

  1. ghost added
    needs-triageWorkflow: This is a new issue that needs to be triaged to the appropriate team.
    on Jun 29, 2022
  2. ghost added
    customer-reportedIssues that are reported by GitHub users external to the Azure organization.
    on Jun 29, 2022
  3. ghost added
    questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that
    on Jun 29, 2022
  4. ghost removed
    needs-triageWorkflow: This is a new issue that needs to be triaged to the appropriate team.
    on Jun 29, 2022
  5. ghost added
    needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK team
    on Jun 29, 2022
  6. added
    ClientThis issue points to a problem in the data-plane of the library.
    and removed
    needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK team
    on Jun 29, 2022
  7. added this to the 2022-07 milestone on Jun 30, 2022
  8. mrm9084 commented on Jun 30, 2022

    @mrm9084
    Member

    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.

    @Component("Vesta.CreditCard")
    @RequestScope
    public class CreditCardFilter implements FeatureFilter {
    
        @Autowired
        private HttpServletRequest request;
    
        @Override
        public boolean evaluate(FeatureFilterEvaluationContext featureFilterEvaluationContext) {
            String binCard       = (String)featureFilterEvaluationContext.getParameters().get("BIN");
    
            CreditCardParametersFilter creditCard = new CreditCardParametersFilter();
            creditCard.setCreditCard((String)request.get("creditCard"));
    
            String binNumberRequest = creditCard.getBINCard();
            return binCard.equals(binNumberRequest);
        }
    }

    It looks like some documentation should be update for the scenario. This is similar to how our TargetingFilter is implemented.

  9. gaderGarcia commented on Jun 30, 2022

    @gaderGarcia
    Author

    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.

  10. gaderGarcia commented on Jul 8, 2022

    @gaderGarcia
    Author

    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

  11. mrm9084 commented on Jul 8, 2022

    @mrm9084
    Member

    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.

    <dependency>
        <groupId>com.azure.spring</groupId>
        <artifactId>spring-cloud-azure-feature-management</artifactId>
        <version>4.0.0-beta.1</version>
    </dependency>

    The beta is for a new our new Dynamic Features work, but it did fix a few things in the original release.

  12. github-actions commented on Jun 28, 2024

    @github-actions
    Contributor

    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.

  13. locked and limited conversation to collaborators on Jun 28, 2024
  14. mrm9084 commented on Oct 10, 2025

    @mrm9084
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

ClientThis issue points to a problem in the data-plane of the library.azure-springAll azure-spring related issuesazure-spring-app-configurationSpring app configuration related issues.customer-reportedIssues that are reported by GitHub users external to the Azure organization.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions