Lambda function A/B Testing with .NET and Function URLs
Want to learn more about AWS Lambda and .NET? Check out my A Cloud Guru course on ASP.NET Web API and Lambda.
Introduction
This post shows how to perform some simple A/B testing with Lambda functions. The functions will be invoked by via a Function URL.
In a recent post, I covered Lambda function versions, it is not required reading for this post, but I won’t be explaining it again here.
The aliases feature of Lambda allows you to assign one or more versions of a function to an alias, and you can choose the percentage of requests that are routed to each version.
In this example, you will deploy two versions of the function, one stable and one experimental. Then assign those versions to an alias. Finally, assign a Function URL to the alias.
1. Create and deploy the function
Follow steps 1-6 in this post to create a Lambda function that can handle HTTPS requests, using the name LambdaABTestingFunctionUrl
instead of SimpleLambdaWithFunctionUrl
.
But change the FunctionHandler(..)
method to -
public APIGatewayHttpApiV2ProxyResponse FunctionHandler(APIGatewayHttpApiV2ProxyRequest request, ILambdaContext context)
{
var response = new APIGatewayHttpApiV2ProxyResponse
{
StatusCode = (int)HttpStatusCode.OK,
Body = $"Stable function",
Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
};
return response;
}
You should now have a Lambda function that can be invoked by a Function URL.
2. Create a stable version of the function
Create a new version of the Lambda function and give it the description “Stable” -
aws lambda publish-version --function-name LambdaABTestingFunctionUrl --description Stable
In the output of the command you will see a version number, note this as the version number of the stable version. It should be version 1.
3. Update the deployed function
Update the FunctionHandler(..)
method, changing the text assigned to the body of the response -
Body = $"Experimental function",
Deploy this using -
dotnet lambda deploy-function LambdaABTestingFunctionUrl
This does not overwrite the stable version.
4. Deploy the experimental version
aws lambda publish-version --function-name LambdaABTestingFunctionUrl --description Experimental
In the output of the command you will see a version number, note this as the version number of the experimental version. It should be version 2.
You now have two versions of the function.
5. Create an alias
If you are using PowerShell use -
aws lambda create-alias --function-name LambdaABTestingFunctionUrl --name ABTest --function-version 1 --routing-config AdditionalVersionWeights=
'{"2"=0.5}'
If you are using Command Prompt or Bash use -
aws lambda create-alias --function-name LambdaABTestingFunctionUrl --name ABTest --function-version 1 --routing-config AdditionalVersionWeights={"2"=0.5}
You will see output that looks like -
{
"AliasArn": "arn:aws:lambda:us-east-1:xxxxxxxxxxx:function:LambdaABTestingFunctionUrl:ABTest",
"Name": "ABTest",
"FunctionVersion": "1",
"Description": "",
"RoutingConfig": {
"AdditionalVersionWeights": {
"2": 0.5
}
},
"RevisionId": "459ef2f2-3843-4ea7-a1a7-eff1e410eca9"
}
Almost there, now all that is needed is to create a Function URL for the alias.
6. Create a Function URL for the alias
Create a Function URL for the alias -
aws lambda create-function-url-config --function-name LambdaABTestingFunctionUrl:ABTest --auth-type NONE
You will get output that looks like -
{
"FunctionUrl": "https://xxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.us-east-1.on.aws/",
"FunctionArn": "arn:aws:lambda:us-east-1:xxxxxxxxxxx:function:LambdaABTestingFunctionUrl:ABTest",
"AuthType": "NONE",
"CreationTime": "2022-08-27T14:18:32.121393Z"
}
Note that the FunctionUrl here will be different than the one you created in step 1. This is because the Function URL is for the alias.
Then add the resource-based policy to allow the Function URL to invoke the Lambda function-
aws lambda add-permission --function-name LambdaABTestingFunctionUrl:ABTest --statement-id AuthNone --action lambda:InvokeFunctionUrl --principal * --function-url-auth-type NONE
7. Test it out
Open the URL in a browser, and keep reloading it. You should see that you invoke the stable version sometimes, and the experimental version sometimes.