diff --git a/.changeset/swift-starfishes-relate.md b/.changeset/swift-starfishes-relate.md new file mode 100644 index 0000000000..967589f88c --- /dev/null +++ b/.changeset/swift-starfishes-relate.md @@ -0,0 +1,5 @@ +--- +'@aws-amplify/backend-function': minor +--- + +adds support for architecture property on defineFunction diff --git a/packages/backend-function/API.md b/packages/backend-function/API.md index 86a98d7e1e..c4e9d7a105 100644 --- a/packages/backend-function/API.md +++ b/packages/backend-function/API.md @@ -15,6 +15,9 @@ export type AddEnvironmentFactory = { addEnvironment: (key: string, value: string | BackendSecret) => void; }; +// @public (undocumented) +export type ArchitectureType = 'x86_64' | 'arm64'; + // @public (undocumented) export type CronSchedule = `${string} ${string} ${string} ${string} ${string}` | `${string} ${string} ${string} ${string} ${string} ${string}`; @@ -29,6 +32,7 @@ export type FunctionProps = { memoryMB?: number; environment?: Record; runtime?: NodeVersion; + architecture?: ArchitectureType; schedule?: FunctionSchedule | FunctionSchedule[]; }; diff --git a/packages/backend-function/src/factory.test.ts b/packages/backend-function/src/factory.test.ts index 316271131e..0e0f594562 100644 --- a/packages/backend-function/src/factory.test.ts +++ b/packages/backend-function/src/factory.test.ts @@ -1,22 +1,22 @@ -import { beforeEach, describe, it, mock } from 'node:test'; -import { App, Stack } from 'aws-cdk-lib'; -import { - ConstructFactoryGetInstanceProps, - ResourceNameValidator, -} from '@aws-amplify/plugin-types'; -import assert from 'node:assert'; import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage'; import { ConstructContainerStub, ResourceNameValidatorStub, StackResolverStub, } from '@aws-amplify/backend-platform-test-stubs'; -import { defaultLambda } from './test-assets/default-lambda/resource.js'; +import { + ConstructFactoryGetInstanceProps, + ResourceNameValidator, +} from '@aws-amplify/plugin-types'; +import { App, Stack } from 'aws-cdk-lib'; import { Template } from 'aws-cdk-lib/assertions'; +import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam'; +import { Runtime } from 'aws-cdk-lib/aws-lambda'; +import assert from 'node:assert'; +import { beforeEach, describe, it, mock } from 'node:test'; import { NodeVersion, defineFunction } from './factory.js'; +import { defaultLambda } from './test-assets/default-lambda/resource.js'; import { lambdaWithDependencies } from './test-assets/lambda-with-dependencies/resource.js'; -import { Runtime } from 'aws-cdk-lib/aws-lambda'; -import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam'; const createStackAndSetContext = (): Stack => { const app = new App(); @@ -334,6 +334,31 @@ void describe('AmplifyFunctionFactory', () => { }); }); + void describe('architectures property', () => { + void it('sets valid architectures', () => { + const lambda = defineFunction({ + entry: './test-assets/default-lambda/handler.ts', + architecture: 'arm64', + }).getInstance(getInstanceProps); + const template = Template.fromStack(Stack.of(lambda.resources.lambda)); + + template.hasResourceProperties('AWS::Lambda::Function', { + Architectures: ['arm64'], + }); + }); + + void it('defaults to x86_64 architecture', () => { + const lambda = defineFunction({ + entry: './test-assets/default-lambda/handler.ts', + }).getInstance(getInstanceProps); + const template = Template.fromStack(Stack.of(lambda.resources.lambda)); + + template.hasResourceProperties('AWS::Lambda::Function', { + Architectures: ['x86_64'], + }); + }); + }); + void describe('schedule property', () => { void it('sets valid schedule - rate', () => { const lambda = defineFunction({ diff --git a/packages/backend-function/src/factory.ts b/packages/backend-function/src/factory.ts index 3feefb4b78..a77e366795 100644 --- a/packages/backend-function/src/factory.ts +++ b/packages/backend-function/src/factory.ts @@ -1,3 +1,9 @@ +import { + FunctionOutput, + functionOutputKey, +} from '@aws-amplify/backend-output-schemas'; +import { AttributionMetadataStorage } from '@aws-amplify/backend-output-storage'; +import { AmplifyUserError, TagName } from '@aws-amplify/platform-core'; import { BackendOutputStorageStrategy, BackendSecret, @@ -12,28 +18,22 @@ import { ResourceProvider, SsmEnvironmentEntry, } from '@aws-amplify/plugin-types'; -import { Construct } from 'constructs'; -import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; -import * as path from 'path'; -import { getCallerDirectory } from './get_caller_directory.js'; import { Duration, Stack, Tags } from 'aws-cdk-lib'; -import { CfnFunction, Runtime } from 'aws-cdk-lib/aws-lambda'; -import { createRequire } from 'module'; -import { FunctionEnvironmentTranslator } from './function_env_translator.js'; +import { Rule } from 'aws-cdk-lib/aws-events'; +import * as targets from 'aws-cdk-lib/aws-events-targets'; import { Policy } from 'aws-cdk-lib/aws-iam'; +import { Architecture, CfnFunction, Runtime } from 'aws-cdk-lib/aws-lambda'; +import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { Construct } from 'constructs'; import { readFileSync } from 'fs'; +import { createRequire } from 'module'; +import { fileURLToPath } from 'node:url'; import { EOL } from 'os'; -import { - FunctionOutput, - functionOutputKey, -} from '@aws-amplify/backend-output-schemas'; +import * as path from 'path'; +import { FunctionEnvironmentTranslator } from './function_env_translator.js'; import { FunctionEnvironmentTypeGenerator } from './function_env_type_generator.js'; -import { AttributionMetadataStorage } from '@aws-amplify/backend-output-storage'; -import { fileURLToPath } from 'node:url'; -import { AmplifyUserError, TagName } from '@aws-amplify/platform-core'; +import { getCallerDirectory } from './get_caller_directory.js'; import { convertFunctionSchedulesToRuleSchedules } from './schedule_parser.js'; -import * as targets from 'aws-cdk-lib/aws-events-targets'; -import { Rule } from 'aws-cdk-lib/aws-events'; const functionStackType = 'function-Lambda'; @@ -109,6 +109,13 @@ export type FunctionProps = { */ runtime?: NodeVersion; + /** + * The architecture of the target platform for the function. + * Defaults to x86_64. + * @see [AWS Lambda architectures](https://docs.aws.amazon.com/lambda/latest/dg/foundation-arch.html) + */ + architecture?: ArchitectureType; + /** * A time interval string to periodically run the function. * This can be either a string of `"every "`, `"every day|week|month|year"` or cron expression. @@ -165,6 +172,7 @@ class FunctionFactory implements ConstructFactory { memoryMB: this.resolveMemory(), environment: this.props.environment ?? {}, runtime: this.resolveRuntime(), + architecture: this.resolveArchitecture(), schedule: this.resolveSchedule(), }; }; @@ -256,6 +264,23 @@ class FunctionFactory implements ConstructFactory { return this.props.runtime; }; + private resolveArchitecture = () => { + // if architecture is not set, default to x86_64 + if (!this.props.architecture) { + return 'x86_64'; + } + + if (!(this.props.architecture in architectureMap)) { + throw new Error( + `architecture must be one of the following: ${Object.keys( + architectureMap + ).join(', ')}` + ); + } + + return this.props.architecture; + }; + private resolveSchedule = () => { if (!this.props.schedule) { return []; @@ -349,6 +374,7 @@ class AmplifyFunction timeout: Duration.seconds(props.timeoutSeconds), memorySize: props.memoryMB, runtime: nodeVersionMap[props.runtime], + architecture: architectureMap[props.architecture], bundling: { format: OutputFormat.ESM, banner: bannerCode, @@ -475,3 +501,9 @@ const nodeVersionMap: Record = { 18: Runtime.NODEJS_18_X, 20: Runtime.NODEJS_20_X, }; + +export type ArchitectureType = 'x86_64' | 'arm64'; +const architectureMap: Record = { + x86_64: Architecture.X86_64, + arm64: Architecture.ARM_64, +};