Closed ran-isenberg closed 2 years ago
@heitorlessa After our chat in slack, I thought i'd advance this by providing a working poc with most of the tests. It's pure python, no pydantic!
https://github.com/awslabs/aws-lambda-powertools-python/pull/494
Update: working on documentation as we speak
Update: working on documentation as we speak
I'm available on Slack for questions
This is now launched as part of 1.19.0 release: https://github.com/awslabs/aws-lambda-powertools-python/releases/tag/v1.19.0
The UX has largely changed and it's now broken down into the following components:
StoreProvider will likely change to make it easier to bring additional providers - AppConfig is the only supported one as we speak. AppConfigStore is using Parameters
utility to reuse caching and AppConfig logic. However, this makes it harder to create other Stores and yet make use of cache and JMESPath for a consistent experience across Stores --- That is the reason is still in Beta.
Full docs with examples are here: https://awslabs.github.io/aws-lambda-powertools-python/latest/utilities/feature_flags/
{
"premium_features": {
"default": false,
"rules": {
"customer tier equals premium": {
"when_match": true,
"conditions": [
{
"action": "EQUALS",
"key": "tier",
"value": "premium"
}
]
}
}
},
"ten_percent_off_campaign": {
"default": false
}
}
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
app_config = AppConfigStore(
environment="dev",
application="product-catalogue",
name="features"
)
feature_flags = FeatureFlags(store=app_config)
def lambda_handler(event, context):
# Get customer's tier from incoming request
ctx = { "tier": event.get("tier", "standard") }
# Evaluate whether customer's tier has access to premium features
# based on `has_premium_features` rules
has_premium_features: bool = feature_flags.evaluate(name="premium_features",
context=ctx, default=False)
if has_premium_features:
# enable premium features
...
from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver
from aws_lambda_powertools.utilities.feature_flags import FeatureFlags, AppConfigStore
app = ApiGatewayResolver()
app_config = AppConfigStore(
environment="dev",
application="product-catalogue",
name="features"
)
feature_flags = FeatureFlags(store=app_config)
@app.get("/products")
def list_products():
ctx = {
**app.current_event.headers,
**app.current_event.json_body
}
# all_features is evaluated to ["geo_customer_campaign", "ten_percent_off_campaign"]
all_features: list[str] = feature_flags.get_enabled_features(context=ctx)
if "geo_customer_campaign" in all_features:
# apply discounts based on geo
...
if "ten_percent_off_campaign" in all_features:
# apply additional 10% for all customers
...
def lambda_handler(event, context):
return app.resolve(event, context)
Schema specification: https://awslabs.github.io/aws-lambda-powertools-python/latest/api/utilities/feature_flags/index.html#aws_lambda_powertools.utilities.feature_flags.SchemaValidator
Rule engine flowchart
I'll keep this open until we go GA so it's easier to catch up on interfaces and such for future implementations ;)
Key information
Summary
[summary]: Simplify the usage of feature toggles with AppConfig. Take it to the next level with a rule engine that provides calculated values of feature toggles according to input context.
Motivation
App config is great but it's very raw/barebones. This feature will encourage people to use AppConfig. I'd like to build a feature toggles on top the current app config utility.
Proposal
Build a simple feature toggle rule engine. The rules will be part of the JSON schema that is uploaded to AppConfig. The rule engine will use existing powertools utility to load and parse the json from AppConfig. It will provide a simple function (same API as launch darkly support) for getting a feature toggle by name. The function will also receive a context dict which will be matched against a set of rules. The feature will have a default boolean value. However, if the context data matches a rule in the schema JSON, the returned value will be the value that is defined in the matched rule. This can allow you to have a feature toggle turned off by default but turning it on for a specific user or customer in a specific region etc. The rules will accept any key/value context. Supported actions can be equals, starts with, regex match , endswith, in a list and many more. It's very easy to extend the engine. An example rule: 'if customer_name' equals coca cola and username starts with 'admin' , trigger the feature on. For other cases, the feature is off. See configuration language below. This type of API will take appconfig to the next level. It's very much barebones at the moment.
If this feature should be available in other runtimes (e.g. Java, Typescript), how would this look like to ensure consistency? It can be done in other languages, it's a very simple rule engine that I've already written in Python.
User Experience
How would customers use it?
conf_store: ConfigurationStore = ConfigurationStore( environment='test_env', service='test_app', conf_name="test_conf_name", cache_seconds=600, )
toggle: bool = conf_store.get_feature_toggle(feature_name='my_feature', rules_context={'customer_name': 'coca-cola', 'username': 'abc'}, default_value=False)
The default value parameter in the API is the default value to return if the feature doesn't exist in the json schema.
Any configuration or corner cases you'd expect?
Example configuration: { 'log_level': 'DEBUG', 'features': { 'my_feature': { 'default_value': 'False', 'rules': [ { 'name': 'set the toggle on for customer name 666 and username abc ', 'default_value': True, 'restrictions': [ { 'action': 'EQUALS', 'key': 'customer_name', 'value': 'coca-cola', }, { 'action': 'EQUALS', 'key': 'username', 'value': 'abc', } ] }, ] } } }
Drawbacks
Current solution has support for only boolean values for feature toggles. This can be of course expanded if required rather easily.
Rationale and alternatives
Alternative is to use a third party tool (which is not free) like Launch Darkly.
What other designs have been considered? Why not them? You can use Launch Darkly. However, this solution is very simple and provides the same client side API that launch darkly provide with AWS AppConfig.
What is the impact of not doing this?
Unresolved questions