Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set my AWS Lambda provisioned capacity to zero in off hours?

I'm using the Serverless framework (serverless.com) and it looks like I can save some pretty serious money by only scaling up the provisioned capacity of my Lambda functions during business hours (9am-5pm, 40 hour per week) and then down to zero during off hours. My application isn't used very much in off hours, and if it is, my users are okay with cold starts and it taking longer.

In my serverless.yml, I have functions declared such as:

  home_page:
    handler: homePage/home_page_handler.get
    events:
      - http:
          path: homePage
          method: get
          cors: true
          authorizer: authorizer_handler
    provisionedConcurrency: 1

I also have a Lambda that runs on a regular basis to set the provisioned capacity of the other Lambdas in the account depending on the time of day. In that Lambda if I call:

await lambda.putProvisionedConcurrencyConfig({
    FunctionName: myFunctionName,
    ProvisionedConcurrentExecutions: 0,
    Qualifier: "provisioned",
  }).promise();

Then I get this error:

Received error:  ValidationException: 1 validation error detected: Value '0' at 'provisionedConcurrentExecutions' failed to satisfy constraint: Member must have value greater than or equal to 1
    at Object.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:52:27)
    at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/rest_json.js:55:8)
    at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
    at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:688:14)
    at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:690:12) {
  code: 'ValidationException',
  time: 2021-08-14T17:45:48.932Z,
  requestId: '8594fad6-d5dd-4a00-adca-c34f9d38b25e',
  statusCode: 400,
  retryable: false,
  retryDelay: 77.81562781029108
}

On the other hand, if I try to delete the provisioned capacity entirely, like this:

  await lambda.deleteProvisionedConcurrencyConfig({
    FunctionName: myFunctionName,
    Qualifier: "provisioned",
  }).promise();

That works fine, but when I try to deploy my function again in off hours (which is the norm), CloudFormation errors out with:

No Provisioned Concurrency Config found for this function (Service: AWSLambdaInternal; Status Code: 404; Error Code: ProvisionedConcurrencyConfigNotFoundException; Request ID: 75dd221b-35d2-4a49-80c5-f07ce261d357; Proxy: null)

Does anybody have a neat solution to turn off provisioned capacity during some hours of the day?

like image 495
Ryan Shillington Avatar asked Sep 19 '25 23:09

Ryan Shillington


1 Answers

After some thinking, if you're still committed to Lambda as the compute solution, I think your best option is to manage provisioned concurrency outside of the Serverless Framework entirely.

You've already got an orchestrator function which will enable provisioned concurrency, you could try removing provisionedConcurrency from your serverless.yml file, adding another method in your orchestrator to disable provisioned currency in the evenings, and verifying that you can deploy when your orchestrator has set your functions to either state.

If you're willing to throw away your orchestrator function, AWS suggests using Application Auto Scaling, which is very useful for exactly what you're doing. (hat tip to @mpv)

That being said, Lambda isn't particularly well suited to predictable, steady-state traffic. If cost is a concern, I'd suggest exploring Fargate or ECS and writing a few autoscaling rules. Your Lambda code is already stateless, and likely is portable and has pretty limited networking rules. There are other forms of compute which would be dramatically cheaper to use.

like image 174
Aaron Stuyvenberg Avatar answered Sep 21 '25 14:09

Aaron Stuyvenberg