3
votes

We are building a serverless app using aws and we want to enable lambda warmers only on the production environment.

Our cloudformation parameters:

Parameters:
  Environment:
    Description: Environment name
    Type: String

  EnableWarmer:
    Description: Flag to enable/disable warmup Events
    Default: DISABLED
    Type: String

Our lambdas yaml file looks like this:

MyLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub '${Environment}-my-lambda'
      CodeUri: src
      Handler: lambda.handler
      Runtime: nodejs12.x
      MemorySize: 128
      Timeout: 100
      Description: Creates a new something
      Layers:
        - !Ref InternalDependencyLayer
        - !Ref ExternalDependencyLayer
      Role: !Ref LambdaRoleArn
      Events:
        Api:
          Type: Api
          Properties:
            Path: /url
            Method: POST
            RestApiId: !Ref ApiGateway
        WarmingSchedule:
          Type: Schedule
          Properties:
            Enabled: !Ref EnableWarmer
            Schedule: rate(5 minutes)
            Input: '{ "warmer":true,  "concurrency": 2 }'

And then we deploy the dev environment with these params:

- Key: Environment
  Value: dev

- Key: EnableWarmer
  Value: DISABLED

Similarly for the production environment we deploy with these params:

- Key: Environment
  Value: production

- Key: EnableWarmer
  Value: ENABLED

According to aws documentation parameters can't be of type boolean which is the required type of the enabled attribute of the schedule event.

Fortunately amazon states:

Enabled Indicates whether the rule is enabled.

To disable the rule, set this property to False.

Type: Boolean

Required: No

AWS CloudFormation compatibility: This property is similar to the State property of an AWS::Events::Rule resource. If this property is set to True then AWS SAM passes ENABLED, otherwise it passes DISABLED

https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-schedule.html

However when we deploy to the dev environment the warmers are enabled.

3

3 Answers

1
votes

According to the documentation, Enabled must a Boolean variable.

You can still have a String parameter and convert it to Boolean inside the CloudFormation.

WarmingSchedule:
  Type: Schedule
    Properties:
      Enabled: !Equals [!Ref EnableWarmer, ENABLED] 
      Schedule: rate(5 minutes)
      Input: '{ "warmer":true,  "concurrency": 2 }'

This way you still can send ENABLED or DISABLED as a parameter but the input of WarmingSchedule.Enabled will be a Boolean.

2
votes

The problem with the Enabled property here seems to be that it does not support using CloudFormation's If function and a Condition to do something like that:

WarmingSchedule:
  Enabled: !If [WarmerCondition, true, false]

(At least I couldn't figure it out, but maybe I just did something wrong) This is similar to what @raul-barreto suggests with !Equals. However, in my tests it always sets the rule's status to ENABLED.

It seems like there are two options left what you can do:

a) (Not recommended) Copy the CloudFormation code of your Lambda function and have a second one available in your CloudFormation resources. Now set a condition to both of them so you only create one of them, depending on your environment. Note: I don't say this is a good approach but it'd be possible. Problems are you have to maintain the definition of both Lambda functions and if you repeat this approach, you'll faster reach CloudFormations template size limits.

b) If you want to make sure you have a minimum number of instances available to your function (at least that's what I interpret from your question), consider using AWS Lambda's Provisioned Concurrency feature instead. You can define it like this in your AWS Lambda function using SAM:

MyLambda:
  Type: AWS::Serverless::Function
  Properties:
    AutoPublishAlias: 'LATEST' #Setting AutoPublishAlias is important, otherwise you can not use provisioned concurrency
    ProvisionedConcurrencyConfig:
      ProvisionedConcurrentExecutions: 2

This snippet will provision concurrency for the function's alias 'LATEST' which points to the latest version of your function. Read more about AutoPublishAlias in SAM (Note: the link's content is written in the context of traffic shifting but it explains what the property does). It makes sure that you always have 2 instances of your Lambda functions available.

0
votes

The accepted solution works, but as stated in comments, it is a bit difficult to control the enabling and disabling of the event. The following seems to work in a more robust way.

      Events:
        Scheduler:
          Type: Schedule 
          Properties:
            Schedule: !If [EnableWarmer, "rate(5 minutes)",
                           "cron(00 00 01 01 ? 1970)"]