amplify-backend icon indicating copy to clipboard operation
amplify-backend copied to clipboard

Amplify Gen 2 Lambda Functions: additional files / modules / lambda layers

Open domthomas1 opened this issue 1 year ago • 5 comments

Environment information

System:
  OS: macOS 14.4.1
  CPU: (12) arm64 Apple M2 Pro
  Memory: 217.09 MB / 32.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 20.9.0 - ~/.nvm/versions/node/v20.9.0/bin/node
  Yarn: undefined - undefined
  npm: 10.1.0 - ~/.nvm/versions/node/v20.9.0/bin/npm
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 0.13.0-beta.14
  @aws-amplify/backend-cli: 0.12.0-beta.16
  aws-amplify: 6.0.25
  aws-cdk: 2.134.0
  aws-cdk-lib: 2.134.0
  typescript: 5.4.3
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables%

Description

In Amplify Gen 2 can we have a way to include additional files including node modules within a lambda function, either using lambda layers and/or an alternate approach

domthomas1 avatar Apr 10 '24 18:04 domthomas1

Hi @domthomas1, dependencies that are imported by your lambda handler code are automatically bundled with your function code. We currently don't have a mechanism to include other assets in the bundled artifact but you could use CDK overrides to create and attach a lambda layer to your function.

Amplify CDK Override docs: https://docs.amplify.aws/gen2/build-a-backend/add-aws-services/overriding-resources/ CDK LayerVersion docs: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.LayerVersion.html#class-layerversion-construct CDK function .addLayer docs: https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.Function.html#addwbrlayerslayers

edwardfoyle avatar Apr 10 '24 19:04 edwardfoyle

Hi @edwardfoyle thanks for your response.

I was able to get some module dependencies included in the lambda as you suggested, although I had to use different approaches depending on the module.

For example, const { Sha256 } = require('@aws-crypto/sha256-js'); worked ok, while the openai module didn't using that approach, and i needed to resort to referencing a copy of the module using import OpenAI from '../openai/nodejs/node_modules/openai/index.mjs';.

It's not clear to me if I should add lambda dependencies to the root package.json under dependencies or devDependencies as this is a back-end component which isn't required in the front-end. Or if I should use another approach if the module isn't found automatically.

The other thing to note is that the dependencies get added to the lambda index.mjs file adding thousands of lines to the original code making traversing the code more difficult. So lambda layers would be a more preferable approach to me. I'll have a deeper dive into the links provided to see if i can work out how to implement layers into Amplify Gen 2, although I'd appreciate any example code that you might be able to provide to help expedite this if possible?

domthomas1 avatar Apr 10 '24 21:04 domthomas1

It's not clear to me if I should add lambda dependencies to the root package.json under dependencies or devDependencies

lambda dependencies can be added as devDependencies because they are only required during build time to bundle the lambda code

should use another approach if the module isn't found automatically

The function code is bundled using esbuild and it should be able to find any module in the node_modules of the project. If you have repro steps for a specific issue here, we can take a look at what's going on.

adding thousands of lines to the original code making traversing the code more difficult

Can you explain your use case for looking at the bundled output? Are you trying to debug a specific issue?

any example code that you might be able to provide

Setting up the lambda layer should look something like the following in your amplify/backend.ts file:

import { myFunc } from './path/to/function/resource';
import { Stack } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';

const backend = defineBackend({
  myFunc,
});

const lambdaFunction = backend.myFunc.resources.lambda as lambda.Function;
const layerVersion = new lambda.LayerVersion(Stack.of(lambdaFunction), 'customLayer', {
  code: lambda.Code.fromAsset('./path/to/layer/directory'),
})
lambdaFunction.addLayers(layerVersion);

edwardfoyle avatar Apr 11 '24 19:04 edwardfoyle

hi @edwardfoyle thanks for your response. However I've been unable to add the openai module as a lambda layer having tried numerous layer paths.

This includes ../node_modules/openai, ./functions/openai, subdirectories and files, and ./functions/openai/nodejs/node_modules/openai/index.mjs. This latter path was the only one I was able to get working when importing the openai module from within the function handler directly, so not using a layer (using import OpenAI from '../openai/nodejs/node_modules/openai/index.mjs';)

code:

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { data } from './data/resource';
import { myDemoFunction } from './functions/my-demo-function/resource';
import { promptHandler } from './functions/prompt-handler/resource';
import { requestHandler } from './functions/request-handler/resource';
import { Stack } from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { storage } from './storage/resource';

const backend = defineBackend({
  auth,
  data,
  myDemoFunction,
  promptHandler,
  requestHandler,
  storage,
});

const lambdaFunction = backend.requestHandler.resources.lambda as lambda.Function;
const layerVersion = new lambda.LayerVersion(Stack.of(lambdaFunction), 'customLayer', {
  code: lambda.Code.fromAsset('./functions/openai'),
})
lambdaFunction.addLayers(layerVersion);

I get the error:

Caused By: Error: Cannot find asset at /Users/dominic/code/amplify/react-amplify-gen2/functions/openai
    at new AssetStaging (/Users/dominic/code/amplify/react-amplify-gen2/node_modules/aws-cdk-lib/core/lib/asset-staging.js:1:2119)

Resolution: Check your backend definition in the `amplify` folder for syntax and type errors.```

domthomas1 avatar Apr 15 '24 09:04 domthomas1

@edwardfoyle Thank you so much for working on amplify and helping us with these questions. I can build a layer, but it seems to be larger than I would like to track in github. So I'm thinking of building the layer by hand and then using the amplify stack to just pull down the zip file when creating the layer or just pull down a prebuilt-custom layer. But I'm not sure how to import an existing layer into my CDK stack (written in typescript.)

Would it be too much to give me some direction on how I might incorporate a prebuilt-custom layer in the CDK in amplify when adding a stack to the backend?

Thanks!

trevor-alder-t1 avatar Apr 25 '24 18:04 trevor-alder-t1

Hey folks, we have a RFC open to enable support for this: https://github.com/aws-amplify/amplify-backend/issues/1549. We would love to hear your feedback on this. Closing this issue.

ykethan avatar Jun 05 '24 19:06 ykethan