-
Notifications
You must be signed in to change notification settings - Fork 152
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
Feature request: Add support for multi-variant AWS AppConfig feature flags #3754
Comments
Hi @HaaLeo, thank you for opening this issue. Looking at the link you shared, and also at the docs, it looks like this feature is only available when interacting with AppConfig via the Lambda extension - if it's not the case, please let me know. At the moment our Parameters utility is based on the AWS SDK AppConfigDataClient - which doesn't seem to support this type of retrieval. We have had some initial conversations with the AppConfig team earlier this year, but we haven't made any concrete plans yet - although the option is very much on the table. To help us with the decision, besides the functional use case that is covered in the issue & links, could you speak a bit more about how you think Powertools could improve or do different than the experience described in the docs (aka using the agent directly?). I have some assumptions/ideas that I'd like to validate before sharing. Thank you! |
Hi @dreamorosi, I think also the developer experience would benefit from adding that feature to powertools directly. I guess we are an example here: Instead of configuring/enabling the agent on the lambda function a developer can just pass an additional option to |
Hey @dreamorosi and @HaaLeo I'd like to add my 2 cents in this discussion! We have an issue open in Python to add support for the AppConfig extension (the one that brings the agent in) to enable access to some features that are not available through the AppConfig/AppConfigData SDK features. It is also true that the extension adds some cold start penalties - this is kind normal for loading extensions - but it seems that this is more performant than SDK calls (read here), especially in Python functions where boto3 needs to load json and other things. The experience for customers remains the same when using the parameter/feature flags utility, but under the hood we essentially encapsulate the HTTP call to call the extension and unlock some new features. To be honest I think this should be a valid improvement for this utility.
Yeah, thats true that cold start can be higher than without extension, but in theory you don't need to worry with the Lambda's bundle size when deploying because you can use the public layer provided by AppConfig team. But of course this will count a few megabytes towards the total size of the Lambda package - which limit is 250MB.
A current limitation of the Python Feature Flags utility is that it only supports Freeform configuration, it does not support FeatureFlags configuration, we need to improve this. If you decide to do this in TS, keep this in mind. I think if we get more positive feedback here we could consider adding support for the AppConfig extension. Thanks |
Yea, 100% agree and thanks for providing more info about the perf impact. I looked at the contents of the extension and it's a single binary around ~9MB so all in all it shouldn't be too bad, but to do a more fair comparison I'd like us/someone to run tests that compare something like this: import { getAppConfig } from '@aws-lambda-powertools/parameters/appconfig';
const config = await getAppConfig({...}); // async outside of handler
export const handler = async () => {} Versus doing the same thing with the extension + agent combination. This way we could observe the actual cold start impact and decide |
I have this performance test somewhere. Let me find it in my AWS account and I will run it again on Monday with the latest version of the extension. I will post the result here. |
Hello, I come with some test results. I'm focusing this test on Python and because of that ColdStart might be a bit different on NodeJS due to the way things are built + AWS SDK, but I understand that the idea of this issue is to check this in a broader view, so I'm running these tests using Python. The code will be provided in the final step, so you can reproduce it on your own if you want. Fetching configurationBoth Powertools and the AppConfig extension support built-in caching when fetching the configuration profile from AppConfig. In Powertools, customers can disable this caching - even though it is not common - while when using the extension, it must cache for at least 1 second. Another difference is that Powertools stores the cache directly in Lambda's memory (it's valid for Python and TS), avoiding any HTTP call, while the extensions store it in the extension (using memory somehow) but require the Lambda code to make an HTTP call to the extension. This make some difference in scenarios where Lambda is reusing the same container for process new requests. In this test, I'm using a 1s cache for both, so we have the closest scenario for testing. While I'm confident with this test, but I know It can affect a little bit the tests because the extension refreshes this cache async, while powertools does sync. graph TD
A[AppConfig Configuration] --> B{Retrieval Method}
B --> |Powertools| C[Cache stored in Lambda memory]
C --> G[Check Lambda Memory Cache]
G --> H[Return Configuration Instantly]
B --> |AppConfig Extension| D[Cache stored in Extension memory]
D --> I[Lambda sends HTTP request to Extension]
I --> J[Extension checks its memory cache]
J --> K[Extension returns cached configuration]
style G fill:#90EE90
style H fill:#90EE90
style I fill:#ADD8E6
style J fill:#ADD8E6
style K fill:#ADD8E6
ColdStart durationThe AppConfig team has improved the extension + agent, and while ColdStart is still a thing, but based on testing there isn't much difference when using the extension or bringing boto3 to a Lambda with 128MB of config. Of course this might change a bit with more memory, but I think it makes sense to use the baseline config for testing. CW Insights Query + Init durationfirst column = log group - the log group using extension
@log,@initDuration,@billedDuration
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1333.98,98
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1288.63,476
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1243.31,108
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1215.59,454
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1209.17,92
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1191.73,495
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1186.04,489
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1184.87,123
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1182.77,474
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1182.34,97
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1173.19,497
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1169.91,178
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1169.59,464
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1161.41,169
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1137.46,104
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1135.02,493
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1134.49,492
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1133.02,493
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1127.53,134
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1125.72,493
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1124.22,88
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1121.46,439
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1121.19,128
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1119.61,490
533568316194:/aws/lambda/appconfig-with-extension-test-HelloWorldFunction-m9emB1J4zccb,1119.19,103
533568316194:/aws/lambda/appconfig-with-powertools-test-HelloWorldFunction-59UIHxzrpvAv,1118,498 Fetching with ColdStartBase on the previous data, when a ColdStart occurs, we can observe that fetching the configuration with the extension is at least 4x faster than fetching it with boto3. That's why while the extension loads the agent and establishes a connection, Powertools (using boto3) needs to make two calls with boto3: Additional featuresUsing the extension, customers can use some advanced features that are not supported by boto3, so we cannot add this support in Powertools. Features such as: multivariant, prefetch list, multiple account recovery using manifest, others. ConclusionI believe we can think about adding a new provider - I don't know the name yet - that uses the AppConfig extension as a backend and we use the same experience as Powertools, which greatly simplifies the customer's development environment. Please let me know if you have any additional questions. CodePowertools + boto3import time
from aws_lambda_powertools.utilities import parameters
from aws_lambda_powertools import Metrics, Tracer
from aws_lambda_powertools.metrics import MetricUnit, MetricResolution
from aws_lambda_powertools.utilities.typing import LambdaContext
metrics = Metrics(namespace="AppConfigLoadTest")
tracer = Tracer()
app_name = "freeform"
env = "dev"
app_profile = "profile-free"
appconf_provider = parameters.AppConfigProvider(environment=env, application=app_name)
@tracer.capture_lambda_handler
@metrics.log_metrics(capture_cold_start_metric=True)
def lambda_handler(event, context: LambdaContext):
start_time = int(time.time() * 1000)
config = appconf_provider.get(app_profile, max_age=1)
print(config)
# End time measurement
end_time = int(time.time() * 1000)
# Calculate and print execution time
execution_time = end_time - start_time
metrics.add_metric(name="GETWITHPOWERTOOLS", unit=MetricUnit.Milliseconds, value=execution_time, resolution=MetricResolution.High)
return {
"statusCode": 200,
"body": "OK"
} Extensionimport time
import requests
from aws_lambda_powertools import Metrics, Tracer
from aws_lambda_powertools.metrics import MetricUnit, MetricResolution
from aws_lambda_powertools.utilities.typing import LambdaContext
metrics = Metrics(namespace="AppConfigLoadTest")
tracer = Tracer()
# Create a global session object
session = requests.Session()
app_name = "freeform"
env = "dev"
app_profile = "profile-free"
@tracer.capture_lambda_handler
@metrics.log_metrics(capture_cold_start_metric=True)
def lambda_handler(event, context: LambdaContext):
start_time = int(time.time() * 1000)
url = f"http://localhost:2772/applications/{app_name}/environments/{env}/configurations/{app_profile}"
response = session.get(url)
config = response.content
print(config)
# End time measurement
end_time = int(time.time() * 1000)
# Calculate and print execution time
execution_time = end_time - start_time
metrics.add_metric(name="GETWITHEXTENSION", unit=MetricUnit.Milliseconds, value=execution_time, resolution=MetricResolution.High)
return {
"statusCode": 200,
"body": "OK"
} |
Use case
AWS AppConfig multi-variant feature flags enable users to implement use cases such as user segmentation or traffic splitting. Those use cases are described in more detail here.
Solution/User Experience
Taking the example found here one could introduce an optional
context
option of typeRecord<string,string|number|boolean>
. Then one could fetch a variant like this:Alternative solutions
Acknowledgment
Future readers
Please react with 👍 and your use case to help us understand customer demand.
The text was updated successfully, but these errors were encountered: