AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 7

AWS Lambda Managed Instances with Java 25 and AWS SAM

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 1 Introduction and sample application

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 1 Introduction and sample application

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 2

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 2 Create Capacity Provider

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 3

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 3 Create Lambda function with LMI compute type

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 4

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 4 Monitoring, unsupported features, challenges and pricing

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 5

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 5 Lambda function initial performance measurements

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 6

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 6 Lambda function performance improvement approaches

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 7

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 7 Implement scheduled scaling

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 7 Implement scheduled scaling

Implement scheduled scaling

Recently, Amazon EventBridge Scheduler added 619 new SDK API actionsOne of these actions adjusts the Lambda function’s minimum and maximum execution environments for Lambda Managed Instances (LMI) on a recurring or one-time schedule. This is useful for predictable traffic patterns, such as scaling up before peak hours and scaling down during off-peak hours. We can use CloudFormation or the latest versions of AWS CDK or AWS CLI to perform this action. In our example, we’ll use AWS CLI to adjust the Lambda Function Scaling Configuration, for which we’ll use the PutFunctionScalingConfig API as a universal target. We’ll use the Lambda function with the name GetProductByIdJava25WithLMI, which we introduced in part 1.

First of all, let’s create an SQS dead-letter queue, which we’ll use for our action:

aws sqs create-queue --queue-name scheduler-dlq

Next, let’s create an EventBridge Scheduler IAM execution role with the name scale-lambda-managed-instances-eventbridge-scheduler-role. This role grants permission to call the lambda:PutFunctionScalingConfig and send the message to the dead-letter queue on our target function.

This is how the trusted policy looks for the IAM role:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "scheduler.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

And this is how the IAM policy looks (use the ARNs of the Lambda function and SQS dead-letter queue here):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "lambda:PutFunctionScalingConfig"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:lambda:{aws_region}:{aws_account_id}:function:GetProductByIdJava25WithLMI:$LATEST.PUBLISHED"
        },
        {
            "Effect": "Allow",
            "Action": [
                "sqs:SendMessage"
            ],
            "Resource": [
                "arn:aws:sqs:{aws_region}:{aws_account_id}:scheduler-dlq"
            ]
        }
    ]
}

Please replace the values of {aws_region} and {aws_account_id} with your own values, and adjust the Lambda function and SQS Queue names if needed.

Now, let’s create the scheduler:

aws scheduler create-schedule \
  --name "ScaleLambdaManagedInstances" \
  --schedule-expression "at(2026-05-18T08:10:00)" \
  --flexible-time-window '{"Mode": "OFF"}' \
  --target '{
     {"DeadLetterConfig": {"Arn": "arn:aws:sqs:{aws_region}:{aws_account_id}:scheduler-dlq"},
    "Arn": "arn:aws:scheduler:::aws-sdk:lambda:PutFunctionScalingConfig",
    "RoleArn": "arn:aws:iam::{aws_account_id}:role/scale-lambda-managed-instances-eventbridge-scheduler-role",
    "Input": "{\"FunctionName\": \"GetProductByIdJava25WithLMI\", \"Qualifier\": \"$LATEST.PUBLISHED\", \"FunctionScalingConfig\": {\"MinExecutionEnvironments\": 5, \"MaxExecutionEnvironments\": 10}}"
  }'

Let’s explain what happens here:

  • First, we create the schedule with the name ScaleLambdaManagedInstances using a one-time schedule (executes at 08:10 on May 18, 2026). You can use other Schedule types in EventBridge Scheduler, like cron-based expressions.
  • Then, we target the PutFunctionScalingConfig Scheduler API as a universal target.
  • Next, we specify the SQS dead-letter queue ARN created above
  • Then, we specify the IAM execution Role ARN created above
  • Next, we specify the new MinExecutionEnvironments and MaxExecutionEnvironments values in the Input payload
  • Finally, as the scheduler input, we specify the name of the Lambda function and its qualifier (usually $LATEST.PUBLISHED), for which we’d like to change the Function Scaling Configuration. In our case, we set MinExecutionEnvironments to 5 and MaxExecutionEnvironments to 10.
  • We can also optionally set the retry policy and encryption.

After creating the schedule, we’ll see something similar in the Amazon EventBridge Scheduler Service:

Create Amazon EventBridge Scheduler-1
Create Amazon EventBridge Scheduler-2

After the scheduler has run, we can verify that the Lambda function Scaling Configuration has changed:

AWS Lambda with LMI changed capacity configuration

It’s also very important to configure the dead-letter queue. First, I didn’t do it, and configured the Lambda function Resource ARN in the IAM policy like arn:aws:lambda:{aws_region}:{aws_account_id}:function:GetProductByIdJava25WithLMI. I observed that the scheduler hasn’t been invoked and saw the errors in Amazon CloudWatch.
By configuring the dead-letter queue, I saw the exact error message:

ERROR_CODE: AccessDeniedException
ERROR_MESSAGE :
	
User: arn:aws:sts::{aws_account_id}:assumed-role/scale-lambda-managed-instances-eventbridge-scheduler-role/f375e2c757da339a8d593587ce800265 
is not authorized to perform: lambda:PutFunctionScalingConfig on resource: 
arn:aws:lambda:{aws_region}:{aws_account_id}:function:GetProductByIdJava25WithLMI:$LATEST.PUBLISHED 
because no identity-based policy allows the lambda:PutFunctionScalingConfig action

With that, it was clear to me that I needed to append $LATEST.PUBLISHED to the ARN of the Lambda function. Please also use Troubleshooting Amazon EventBridge Scheduler, in case you experience some issues.

Here, we scaled up the capacity at the given time, the same way we can scale it down. Things to pay attention to:

  • For workloads with predictable peaks, create multiple schedules to match your traffic pattern: one to scale up your function before peak hours, and another to scale down after peak hours. Each schedule follows the same pattern with updated MinExecutionEnvironments and MaxExecutionEnvironments values.
  • Scheduled scaling adjusts the provisioned floor and ceiling of execution environments, but actual scaling between min and max still responds to CPU utilization and concurrency saturation.
  • If your traffic more than doubles within 5 minutes of a scheduled scale-up, you might still experience throttling as capacity is provisioned.
  • When scaling to zero to deactivate a function, remember that reactivation requires an explicit PutFunctionScalingConfig call with non-zero values.

AWS Lambda Managed Instances with Java 25 and AWS SAM

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 6 Lambda function performance improvement approaches