-
Notifications
You must be signed in to change notification settings - Fork 100
Description
Environment information
System:
OS: macOS 15.6.1
CPU: (10) arm64 Apple M2 Pro
Memory: 225.67 MB / 16.00 GB
Shell: /bin/zsh
Binaries:
Node: 22.13.1 - ~/.nvm/versions/node/v22.13.1/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 10.9.2 - ~/.nvm/versions/node/v22.13.1/bin/npm
pnpm: undefined - undefined
NPM Packages:
@aws-amplify/auth-construct: 1.8.1
@aws-amplify/backend: 1.16.1
@aws-amplify/backend-ai: Not Found
@aws-amplify/backend-auth: 1.7.1
@aws-amplify/backend-cli: 1.7.2
@aws-amplify/backend-data: 1.6.1
@aws-amplify/backend-deployer: 2.1.1
@aws-amplify/backend-function: 1.14.1
@aws-amplify/backend-output-schemas: 1.6.0
@aws-amplify/backend-output-storage: 1.3.1
@aws-amplify/backend-secret: 1.4.0
@aws-amplify/backend-storage: 1.4.1
@aws-amplify/cli-core: 2.1.1
@aws-amplify/client-config: 1.7.0
@aws-amplify/data-construct: 1.16.1
@aws-amplify/data-schema: 1.21.0
@aws-amplify/deployed-backend-client: 1.7.0
@aws-amplify/form-generator: 1.2.1
@aws-amplify/model-generator: 1.2.0
@aws-amplify/platform-core: 1.9.0
@aws-amplify/plugin-types: 1.10.1
@aws-amplify/sandbox: 2.1.2
@aws-amplify/schema-generator: 1.4.0
@aws-cdk/toolkit-lib: 0.3.2
aws-amplify: 6.14.4
aws-cdk-lib: 2.189.1
typescript: 5.8.3
npm warn exec The following package was not found and will be installed: cdk@2.1029.0
No AWS environment variables
No CDK environment variables
Describe the bug
When deploying a Lambda with Amplify Gen 2 that uses awslambda.streamifyResponse
for response streaming, the function never terminates. Invocation times out even though responseStream.end()
has been called.
Inspection of the transpiled bundle shows Amplify injecting SSM environment variable resolution logic that sets up a recurring setInterval
to refresh SSM parameters every 60 seconds. This interval is not unref()
’d and pins the Node.js event loop, preventing the Lambda runtime from completing.
Setting context.callbackWaitsForEmptyEventLoop = false
allows the function to exit, but that only hides the root issue: it causes Lambda to freeze open handles across warm invocations, creating the risk of timers, sockets, or subscriptions leaking between requests.
Reproduction steps
- Create a new Amplify Gen 2 backend.
- Create a (simplified) Lambda function handler:
// handler.ts
export const handler = awslambda.streamifyResponse(async (_event, stream, _context) => {
stream.write("Hello ");
stream.write("world");
stream.end();
});
- Define the Amplify function with a secret:
// resource.ts
import { defineFunction, secret } from '@aws-amplify/backend';
const streamFunction = defineFunction({
name: 'StreamFunction',
runtime: 22,
entry: './handler.ts',
timeoutSeconds: 60,
environment: {
SOME_SECRET: secret('SOME_SECRET'),
},
});
- Attach a Function URL and enable Invoke mode
RESPONSE_STREAM
.
// backend.ts
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { streamFunction } from './resource';
const backend = defineBackend({
...,
streamFunction
});
backend.streamFunction.resources.lambda.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE,
invokeMode: lambda.InvokeMode.RESPONSE_STREAM,
});
- Deploy.
- Invoke the Function URL, e.g.
curl https://342dqyq5y5d3yq5gd35df3tg.lambda-url.eu-west-1.on.aws/
. - Observe the Lambda runs until timeout and never completes (in CloudWatch Logs), even though the client receives a full response.
Inspecting the built index.mjs
shows Amplify injecting:
const SSM_PARAMETER_REFRESH_MS = 1000 * 60;
setInterval(async () => {
try { await internalAmplifyFunctionResolveSsmParams(); }
catch (error) { console.debug(error); }
}, SSM_PARAMETER_REFRESH_MS);
This timer keeps the event loop alive indefinitely.
Expected behavior
A streaming Lambda should terminate after stream.end()
once response transmission is complete, without requiring callbackWaitsForEmptyEventLoop = false
.