Miłosz Pigłas

Home Facebook Login SDK Notes Contact

Automatic throttling AWS Lambda

Public urls for Lambda functions are relatively new feature in that AWS service. It might super useful when you create function and want to provide it fast. You can create URL with one click fin AWS Management Console and call it with curl. Without fighting with API Gateway configuration.

This approach has one drawback. If some bad actor will find url of your function it might cost you a lot. Everythink depends how your function is configured, but with default settings allow unlimited executions.The good news is that with Cloudwatch support you can setup throttling function, that will temporary disable Lambda function, if it receives too many requests.

Function with URL

Let's create Lambda function hello-url-fn

import json

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }

and configure function url NONE auth type. Lambda service will automatically generate unique function url. Let's assume it is https://hello.lambda-url.eu-central-1.on.aws.You can open it in web browser and check if function sends response.

Configure Cloudwatch alarm

In next step we will create Cloudwatch alarm url-request-alarm, that will be triggered when function hello-url-fn will receive too many request. Requests count can be measured with metric Lambda/UrlRequestCount. Our alarm will be triggered if function will be receiving more than 9 requests / minute in last 5 minutes. If function receive less requests in one minute, then alarm will come back to normal state.

On every change of alarm's state, it will send notification to SNS topic url-request-alarm-topic.

Throttle function

The last puzzle piece is another Lambda function throttle-fn, that is triggered by notification from SNS topic url-request-alarm-topic.

import json
import boto3

def lambda_handler(event, context):
    client = boto3.client('lambda')
    subject = event['Records'][0]['Sns']['Subject']
    executions = 1
    if subject.startswith('ALARM'):
        executions = 0
        print('Disble')
    else:
        print('Enable')
    client.put_function_concurrency(
        FunctionName='hello-url-fn',
        ReservedConcurrentExecutions=executions
    )
    return {
        'statusCode': 200,
        'body': ''
    }

Every Cloudwatch notification has specific structure. We will use Subject property to identify new state of alarm url-request-alarm. If subject starts with phrase ALARM we assume, that state has changed from OK to ALARM. It means, that in last 5 minutes function was receiving more than 9 requests per minute and must be disabled. If subject doesn't start with word ALARM then we assume, that state has changed from ALARM to OK and hello-url-fn can be activated again.

We disable or enable Lambda function by changing reserved concurrency level. That property specifies, how many instances of function can be run at the same time. If reserved concurrency is equal to 0, then all incoming requests are throttled and function is never invoked.

Conclusion

Fuction URL for AWS Lambda is useful feature, but misused might expose you to high costs. For that reason lambda with public url must be carefuly monitored. If we configure alarm with reasonable threshold we will be notified soon enough to make proper action.