This was confirmed to be a bug in Lambda Function URLs. The fix was deployed around or before June 1, 2022 and provisioned concurrency for Function URLs no longer causes 400 status code / ThrottlingException responses if the number of concurrent requests sent is higher than the provisioned concurrency of the Function URL associated with a Lambda version or alias.
This repository contains an example of a possible bug with Lambda Provisioned Concurrency where the function will not scale above the Provisioned Concurrency value, even with Reserved Concurrency set far higher (to account-level unreserved concurrency).
This behavior does not match what is expected and it is demonstrated that an ALB pointing to a Provisioned Concurrency Lambda Alias does not reject requests with a 400 response code beyond the Provisioned Concurrency value. This seems to confirm that there may be a bug with Function URLs that have Provisioned Concurrency set.
Indications of the error:
- 400 Status Code on response
x-amzn-ErrorType: ThrottlingException
header on response{"message":"Rate Exceeded."}
response body
The CDK stack deploys 2 different examples both with an ALB and a Function URL:
- Docker-based Lambda built for ARM64
- Zip-based Lambda built for ARM64
The AWS Lambda URLs are configured with security set to lambda.FunctionUrlAuthType.NONE
so they are open to any caller on the Internet. If this violates your security policies, change the type from lambda.FunctionUrlAuthType.NONE
to lambda.FunctionUrlAuthType.AWS_IAM
, then use awscurl
instead of curl
to test the function invocation.
nvm use
npm i
npm run build
npm run build:rollup
docker-compose build
docker-compose up
# At this point the service should be up but will not be initialized until first request
# To get a shell, if needed, when `docker-compose up` is running:
docker-compose exec app /bin/sh
# To send a test request to the local instance:
npm run test-local-request
# To deploy to an AWS account
npx cdk deploy
# Invoke the Lambda Function URL
curl -v [paste the URL here]
# Invoke the Lambda ALB URL
curl -v [paste the URL here]
Test concurrency limits using ab
(apache bench) or hey
(arguments are the same for both).
hey - Can be installed as a precompiled binary or via brew install hey
on Mac.
The default provisioned concurrency of the Lambda Aliases is 5
.
In general, test the following:
- Run with
-c
(concurrent requests) equal to provisioned concurrency- In this case there should be no
400
status code responses from any URL
- In this case there should be no
- Run with
-c
much larger than provisioned concurrency (e.g.-c 100
)- In this case the
$LATEST
ALB URL, Provisioned Alias ALB URL, and$LATEST
Function URL should return no400
status code responses - The Provisioned Alias Function URL will return a large portion of
400
status code responses and will never improve (it's not an issue of needing to start more instances... it simply will not start more instances or send more thanprovisioned concurrency
requests to the function)
- In this case the
hey -c 100 -n 1000 https://[function-url-id].lambda-url.us-east-1.on.aws/
Result: OK
Result: OK
Result: OK
Result: OK
Result: FAILS - 98% of requests return a 400
status code
curl -v "https://[lambda-provisioned-alias-url].lambda-url.us-east-1.on.aws/"
> GET / HTTP/1.1
> Host: [lambda-provisioned-alias-url].lambda-url.us-east-1.on.aws
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Date: Wed, 11 May 2022 01:08:24 GMT
< Content-Type: application/json
< Content-Length: 28
< Connection: keep-alive
< x-amzn-RequestId: 1db11618-724e-4940-83ce-f5e4069c7593
< x-amzn-ErrorType: ThrottlingException
<
* Connection #0 to host [lambda-provisioned-alias-url].lambda-url.us-east-1.on.aws left intact
{"message":"Rate Exceeded."}