Skip to content
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

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

Closed
gaderGarcia opened this issue Jun 29, 2022 · 5 comments
Assignees
Labels
azure-spring All azure-spring related issues azure-spring-app-configuration Spring app configuration related issues. Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Milestone

Comments

@gaderGarcia
Copy link

gaderGarcia commented Jun 29, 2022

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

@ghost ghost added needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Jun 29, 2022
@hui1110 hui1110 added the azure-spring All azure-spring related issues label Jun 29, 2022
@ghost ghost removed the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label Jun 29, 2022
@hui1110 hui1110 added the azure-spring-app-configuration Spring app configuration related issues. label Jun 29, 2022
@ghost ghost added the needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team label Jun 29, 2022
@hui1110 hui1110 added Client This issue points to a problem in the data-plane of the library. and removed needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team labels Jun 29, 2022
@hui1110 hui1110 added this to the 2022-07 milestone Jun 30, 2022
@mrm9084
Copy link
Member

mrm9084 commented 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.

@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.

@gaderGarcia
Copy link
Author

Hi @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
Copy link
Author

gaderGarcia commented 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
Copy link
Member

mrm9084 commented 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.

<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.

Copy link

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.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 28, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Jun 28, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
azure-spring All azure-spring related issues azure-spring-app-configuration Spring app configuration related issues. Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Projects
None yet
Development

No branches or pull requests

4 participants