Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provisioned Concurrency for Lambda Functions #4865

Closed
jadenv opened this issue Jul 17, 2020 · 14 comments
Closed

Provisioned Concurrency for Lambda Functions #4865

jadenv opened this issue Jul 17, 2020 · 14 comments
Labels
feature-request Request a new feature functions Issues tied to the functions category p4

Comments

@jadenv
Copy link

jadenv commented Jul 17, 2020

Which Category is your question related to?
Functions

Amplify CLI Version
4.24.2

What AWS Services are you utilizing?
API + Functions

Provide additional details e.g. code snippets
Is there a way to configure Provisioned Concurrency for Lambda Functions within the amplify-cli as documented here?
https://aws.amazon.com/blogs/aws/new-provisioned-concurrency-for-lambda-functions/

The biggest issue seems to be that you can't allocate provisioned concurrency on an alias that points to the unpublished version ($LATEST), so not sure how that would work in the cloudformation template as I don't believe you can reference a published version, but maybe I'm wrong about that.

Either way, does anybody have an example of how to do this? Cheers 🍻

@UnleashedMind UnleashedMind added question General question functions Issues tied to the functions category enhancement and removed question General question labels Jul 20, 2020
@UnleashedMind
Copy link
Contributor

We don't provide this out of the box.
I will mark this as en enhancement.

@dseeker
Copy link

dseeker commented Jul 28, 2020

Also looking for a solution using Amplify
@jadenv the serverless framework supports this by passing a single value in provisionedConcurrency, you may want to look how they do it.

@jadenv
Copy link
Author

jadenv commented Jul 28, 2020

@dseeker thats exactly what I did :)

Until this is officially implemented in amplify-cli, I was able to modify my cloudformation template to include a version and alias that allows me to use provisioned concurrency like this:

{
  ...
  "Resources": {
    "LambdaFunction": {
      "Type": "AWS::Lambda::Function",
      ....
    },
    "LambdaVersion": {
      "Type": "AWS::Lambda::Version",
      "DeletionPolicy": "Retain",
      "Properties": {
        "FunctionName": {
          "Ref": "LambdaFunction"
        }
      }
    },
    "ProvisionedConcurrencyLambdaAlias": {
      "Type": "AWS::Lambda::Alias",
      "Properties": {
        "FunctionName": {
          "Ref": "LambdaFunction"
        },
        "FunctionVersion": {
          "Fn::GetAtt": [
            "LambdaVersion",
            "Version"
          ]
        },
        "Name": "provisioned",
        "ProvisionedConcurrencyConfig": {
          "ProvisionedConcurrentExecutions": 20
        }
      },
      "DependsOn": "LambdaFunction"
    }
  }
}

@tomhirschfeld
Copy link
Contributor

@jadenv did you connect your lambda to API gateway at all? I'm having trouble here as API gateway doesn't integrate with the alias that has provisioned concurrency, it connects to "latest", not sure what changes i need to make here

@jadenv
Copy link
Author

jadenv commented Sep 24, 2020

@tomhirschfeld yep, you will have to add :provisioned to the uri of the API CloudFormation template.

Ex:

{
  ...
  "uri": {
    "Fn::Join": [
      "",
      [
        "arn:aws:apigateway:",
        {
          "Ref": "AWS::Region"
        },
        ":lambda:path/2015-03-31/functions/",
        {
          "Ref": "functionlambdaArn"
        },
        ":",
        "provisioned",
        "/invocations"
      ]
    ]
  }
  ...
}

@poulter7
Copy link

@jadenv where in the standard amplify stack does this live? I see the cloudformation-template.json for api/graphql is auto-generated under the /build directory, I expect this gets overridden in each publish?

@poulter7
Copy link

Actually if one is looking to map into the alias from a graphql function I think you can simply pass the alias in the function name.
This points to $Latest
function(...): AWSJSON! @function(name: "function-${env}")
This points to the provisioned alias you mentioned above.
function(...): AWSJSON! @function(name: "function-${env}:provisioned")

@arbermejo0417
Copy link

Hi @jadenv I tried a set up in cloudformation as you suggested for both the Function and API templates. The new resources were created correctly (alias, version and concurrency configurations). But API calls are not invoking the new version. Concurrency still doesn't work. Besides the edit in the API and Function CloudFormation templates you suggested is there anything else I should do?

@siegerts siegerts added feature-request Request a new feature and removed enhancement labels Sep 3, 2021
@dconlon-wagetap
Copy link

Worth making it clear if anyone else stumbles on this, the proposed solution doesn't fully work. This will publish a single LambdaVersion and Alias once, and will not update with subsequent changes.

@dconlon-wagetap
Copy link

dconlon-wagetap commented Oct 12, 2021

However...there is a potential workaround(not battle-tested and not for the faint of heart). Here is a rough sketch of a solution that seems to work for me

Step1

amplify add function

Step 2

Alter the cf template of the function to export s3Key(CF template Output). (this changes if the contents of the lambda changes, i.e. you want to publish a new version)

   "Outputs": {
      "Name": {
        "Value": {
          "Ref": "LambdaFunction"
        }
      },
      "Arn": {
        "Value": {
          "Fn::GetAtt": [
            "LambdaFunction",
            "Arn"
          ]
        }
      },
      "Region": {
        "Value": {
          "Ref": "AWS::Region"
        }
      },
      "s3Key": {
        "Value": {
          "Ref": "s3Key"
        }
      },

Step 3

Create a new custom resource (https://docs.amplify.aws/cli/usage/customcf/) name it what you want, but ensure that it depends on the function you want to have provisioned concurrency (Name and your newly exported s3Key)

Step 4

Make the cf template include these two sections;

       "LambdaDeploy": {
        "Type": "Custom::LambdaVersion",
        "Properties": {
          "ServiceToken": {
            "Ref": "functionlambdaversionerArn"
          },
          "FunctionName": {
            "Ref": "functionmyfunctionName"
          },
          "Description": {
            "Fn::Join": [
              "-",
              [
                "lambdaversion",
                {
                  "Fn::Select": [
                    2,
                    {
                      "Fn::Split": [
                        "-",
                        {
                          "Ref": "functionmyfunctionnames3Key"
                        }
                      ]
                    }
                  ]
                }
              ]
            ]
          }
        }
      },
      "LambdaAlias": {
        "Type": "AWS::Lambda::Alias",
        "Properties": {
          "FunctionName": {
            "Ref": "functionmyfunctionnameName"
          },
          "FunctionVersion": {
            "Fn::GetAtt": ["LambdaDeploy", "Version"]
          },
          "ProvisionedConcurrencyConfig": {
            "ProvisionedConcurrentExecutions": 1
          },
          "Name": "pc"
        },
        "DependsOn": ["LambdaDeploy"]
      }
    },

Step 5

Create new lambda (amplify add function) lambdaversioner with contents that look like,

    exports.handler = (event, context) => {
    console.log('Request received:', JSON.stringify(event)); // Print params so you can manually recover
    const cf = require('cfn-response');
    if (event.RequestType == 'Delete') {
      return cf.send(event, context, "SUCCESS");
    }
    const AWS = require('aws-sdk');
    const lambda = new AWS.Lambda();
    const res = lambda
      .publishVersion({FunctionName: event.ResourceProperties.FunctionName})
      .promise()
      .then(data => {
        return cf.send(
          event,
          context,
          "SUCCESS",
          {Version: data.Version},
          data.FunctionArn,
        );
      })
      .catch(e => {
        return cf.send(event, context, "FAILED", e);
      });
  };

See docs, https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html

Step 6

Don't forget to 'amplify env pull' because backend-config.json changed

Obviously any feedback anyone has, on the pitfalls of this approach, would be greatly appreciated.

@josefaidt josefaidt added the p4 label Mar 16, 2022
@franklin113
Copy link

franklin113 commented Jun 14, 2022

I am looking to add concurrency to my amplify app. Has there been any updates on this?
I have a REST API category lambda function that I want to have concurrency for. I was able to manually assign a lambda version alias to the API Gateway's integration request.

Now I need publish a new version and assign the alias to it when I push to production. How can I achieve this?

@mindgrub-rkoch
Copy link

Is there any update on this feature-request?

@jadenv
Copy link
Author

jadenv commented May 13, 2024

Seeing as this issue has been open for almost 4 years now, it seems this might be a bit too advanced of a use case for Amplify.

I would recommend using AWS CDK as an alternative to configure Lambda autoscaling:

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html#autoscaling

@jadenv jadenv closed this as completed May 13, 2024
Copy link

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request a new feature functions Issues tied to the functions category p4
Projects
None yet
Development

No branches or pull requests