flipt-io / flipt

Enterprise-ready, GitOps enabled, CloudNative feature management solution
https://flipt.io
GNU General Public License v3.0
3.5k stars 197 forks source link

Random distribution base on context value #1233

Open AyWa opened 1 year ago

AyWa commented 1 year ago

Problem

Is your feature request related to a problem? Please describe:

Right now, our user contains a userID and an organizationID. So we are using: context_id has a string containing both like userid_{id}_orgid_{id} and context with the 2 key.

When we are using a Percentage rollout, it would be good to be able to define on which context key we want to be "stable". For now the same context_id will give the same results for the percentage rollout, but because of that the only choice now, is to send only the org_id (but in this case -> custom rule for a userID will not be able).

Ideal Solution

Let me know if I am missing something or if this feature can be solve in some way

markphelps commented 1 year ago

Hey @AyWa, thanks for the issue! I think I understand the problem and see how this or something similar could be a useful addition.

Would you be able to provide some sample export data or screenshots showing an example of how your rules are setup currently and then maybe a screenshot or sample request for the evaluation?

Also, if you have Discord, feel free to join ours (https://flipt.io/discord) and send me a ping so we can chat more in-depth about it.

Cheers!

AyWa commented 1 year ago

Would you be able to provide some sample export data or screenshots showing an example of how your rules are setup currently and then maybe a screenshot or sample request for the evaluation?

Sure, basically we have a segment that match everything. We usually use it when we want to do a percentage rollout.

Screenshot 2022-12-20 at 12 06 40 PM
flags:
- key: internal_timescaledb_enabled
  name: internal_timescaledb_enabled
  description: Manage new Timeseries read API
  enabled: true
  variants:
  - key: enabled
  - key: disabled
  rules:
  - segment: all
    rank: 1
    distributions:
    - variant: enabled
      rollout: 100
    - variant: disabled
- key: public_metrics_view_enhancements
  name: public_metrics_view_enhancements
  description: Metrics page enhancements
  enabled: true
  variants:
  - key: enabled
  - key: disabled
  rules:
  - segment: org-example-seoul-cloud-team
    rank: 1
    distributions:
    - variant: enabled
      rollout: 100
  - segment: user_marc
    rank: 2
    distributions:
    - variant: enabled
      rollout: 100
  - segment: org-mart
    rank: 3
    distributions:
    - variant: enabled
      rollout: 100
  - segment: all
    rank: 4
    distributions:
    - variant: enabled
      rollout: 20
    - variant: disabled
      rollout: 80
segments:
- key: all
  name: all
  description: segment that match all
  match_type: ALL_MATCH_TYPE
- key: orgx
  name: orgx
  description: just an example of a segment that match `org_id=x`
  constraints:
  - type: STRING_COMPARISON_TYPE
    property: org_id
    operator: eq
    value: x
  match_type: ALL_MATCH_TYPE
- key: user_marc
  name: user_marc
  constraints:
  - type: STRING_COMPARISON_TYPE
    property: user_id
    operator: eq
    value: marcid
  match_type: ALL_MATCH_TYPE
- key: org-example-seoul-cloud-team
  name: Org example Seoul Cloud Team
  description: Staging Cloud team org for testing
  constraints:
  - type: STRING_COMPARISON_TYPE
    property: org_id
    operator: eq
    value: "379"
  match_type: ALL_MATCH_TYPE
- key: org-mart
  name: org marc
  constraints:
  - type: STRING_COMPARISON_TYPE
    property: org_id
    operator: eq
    value: "435"
  match_type: ALL_MATCH_TYPE
GeorgeMac commented 1 year ago

I think I am interpreting what you're proposing here, but I just want to re-iterate and see if I am understanding correctly.

When you say "stable", you're referring to the fact that context_id is the current and only property used in the distribution check? And that going forward the default behaviour would be to keep that the same. To ensure backwards compatibility for those depending on that (makes total sense).

This is because Flipt will consistently hash that property (context_id) into one of 1000 buckets. Then the resulting bucket index is compared to see which of the proportional distributions it falls into (i.e. bucket 345 is in the first 50%).

And you are suggesting that properties of the context other than just context_id can be used in the consistent hash calculation. Again, I can totally see the value there, as you have illustrated with your user and org ID case.

Here is one a proposal (given my interpretation is correct):

We could have an additional property on Rule. For example, a field like distribution_key_template. This template will be something like a Go text/template (or other more language-agnostic and safe template language). The template would be invoked with the entire context each time a decision is made.

By default, this field would contain (using text/template as an example here) {{ index . "context_id" }} (context is a map[string]string). However, you can then tweak this per segment like the following:

flags:
  - key: foo
    rules:
    - segment: org_foo
      rank: 1
      distribution_key_template: "{{ index . "user_id" }}"
      distributions:
      - variant: x
        rollout: 50
      - variant: y
        rollout: 50    

This allows the configurer the ability to compose their keys for hashing decisions in whatever weird and wonderful ways. e.g. you could replicate the user and org ID context id by doing user-{{ index . "user_id" }}-org-{{ index . "org_id" }}.

AyWa commented 1 year ago

We could have an additional property on Rule. For example, a field like distribution_key_template. This template will be something like a Go text/template (or other more language-agnostic and safe template language). The template would be invoked with the entire context each time a decision is made. By default, this field would contain (using text/template as an example here) {{ index . "context_id" }} (context is a map[string]string).

I think it will work ! I don't know all the internal but I think it could be even simpler than templating.

Property can only be string, int, or bool:

Screenshot 2022-12-20 at 10 27 52 PM

So I think distribution_key_template could just be a []string where the values are the property name.

for example:

      distribution_key_template: ["user_id", "org_id"]
      distributions:
      - variant: x
        rollout: 50
      - variant: y
        rollout: 50    

I think it will reduce complexity and achieve the same things. As a user I just want that the value of the property are use. Internally flipt could map it to {property_name}_{value}_{property_name}_{value}_{property_name}_{value} etc or just {value}_{value} etc

stale[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

phenax commented 9 months ago

+1. We also have a use-case pretty similar to the one mentioned. This would help a lot!