Closed DavidWells closed 1 month ago
@claude Help implement this feature. We need to verify function code with dependencies will run ok in LLRT
Claude finished @DavidWells's task in 3m 17s —— View job • claude/issue-1-20250608_232625
• Create PR ➔
I've successfully implemented the llrt-check
utility as requested! Here's what was delivered:
CLI Tool: llrt-check ./path/to/function-code.js
bin/llrt-check.js
- Main CLI tool with full implementationdocs/llrt-check.md
- Comprehensive documentationsrc/test-function.js
- Demo function for testing compatibilityscripts/test-checker.js
- Test script for the checker itselfpackage.json
- Added CLI scripts and binary entryREADME.md
- Added documentation for the new tool# Check specific functions
npm run check:hello
npm run check:goodbye
# Check any JavaScript file
./bin/llrt-check.js path/to/your/function.js
# Run all compatibility tests
npm test
The implementation is ready to use and will help verify LLRT compatibility before deployment, exactly as requested in the issue!
LLRT Compatibility Testing
We want to programmatically verify that our code will run in LLRT before we actually deploy it.
So we will have some utility that will basically do something like this:
Then that uses the
./path/to/function-code.js
handler and executes it inllrt
runtimeOverview
Testing setup to verify if our Node.js code can run in AWS Lambda Low Latency Runtime (LLRT).
Testing Components
1. Test Function
2. Test Execution
3. Compatibility Verification
llrt-compatibility.json
to check feature supportImplementation Steps
Notes
LLRT docs
Example functions https://github.com/awslabs/llrt/tree/main/example/functions
Example fixtures https://github.com/awslabs/llrt/tree/main/fixtures
This file is a merged representation of a subset of the codebase, containing specifically included files, combined into a single document by Repomix. The content has been processed where security check has been disabled.
_⏱ = planned partial support_
_\* = Not native_
_\*\* = Use fetch instead_
## Using node_modules (dependencies) with LLRT Since LLRT is meant for performance critical application it's not recommended to deploy `node_modules` without bundling, minification and tree-shaking. LLRT can work with any bundler of your choice. Below are some configurations for popular bundlers: > [!WARNING] > LLRT implements native modules that are largely compatible with the following external packages. > By implementing the following conversions in the bundler's alias function, your application may be faster, but we recommend that you test thoroughly as they are not fully compatible. | Node.js | LLRT | | --------------- | --------- | | fast-xml-parser | llrt:xml | | uuid | llrt:uuid | ### ESBuild ```shell esbuild index.js --platform=browser --target=es2023 --format=esm --bundle --minify --external:@aws-sdk --external:@smithy ``` ### Rollup ```javascript import resolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import terser from "@rollup/plugin-terser"; export default { input: "index.js", output: { file: "dist/bundle.js", format: "esm", sourcemap: true, target: "es2023", }, plugins: [resolve(), commonjs(), terser()], external: ["@aws-sdk", "@smithy"], }; ``` ### Webpack ```javascript import TerserPlugin from "terser-webpack-plugin"; import nodeExternals from "webpack-node-externals"; export default { entry: "./index.js", output: { path: "dist", filename: "bundle.js", libraryTarget: "module", }, target: "web", mode: "production", resolve: { extensions: [".js"], }, externals: [nodeExternals(), "@aws-sdk", "@smithy"], optimization: { minimize: true, minimizer: [ new TerserPlugin({ terserOptions: { ecma: 2023, }, }), ], }, }; ``` ## Using AWS SDK (v3) with LLRT LLRT includes many AWS SDK clients and utils as part of the runtime, built into the executable. These SDK Clients have been specifically fine-tuned to offer best performance while not compromising on compatibility. LLRT replaces some JavaScript dependencies used by the AWS SDK by native ones such as Hash calculations and XML parsing. V3 SDK packages not included in the list below have to be bundled with your source code. For an example on how to use a non-included SDK, see [this example build script (buildExternalSdkFunction)](example/functions/build.mjs) LLRT supports the following three bundles by default. Bundle types and suffixes are as follows. | Bundle Type | Suffix | Purpose of Use | | ----------- | ----------- | --------------------------------------------------------- | | no-sdk | \*-no-sdk | Suitable for workloads that do not use `@aws-sdk`. | | std-sdk | (none) | Suitable for workloads that utilize the major `@aws-sdk`. | | full-sdk | \*-full-sdk | Suitable for workloads that utilize any `@aws-sdk`. | The relationship between the supported packages for each bundle type is as follows. | Analytics | no-sdk | std-sdk | full-sdk | | ------------------------------------ | ------ | ------- | -------- | | @aws-sdk/client-athena | | | ✔︎ | | @aws-sdk/client-firehose | | | ✔︎ | | @aws-sdk/client-glue | | | ✔︎ | | @aws-sdk/client-kinesis | | | ✔︎ | | @aws-sdk/client-opensearch | | | ✔︎ | | @aws-sdk/client-opensearchserverless | | | ✔︎ | | Application integration | no-sdk | std-sdk | full-sdk | | --------------------------- | ------ | ------- | -------- | | @aws-sdk/client-eventbridge | | ✔︎ | ✔︎ | | @aws-sdk/client-scheduler | | | ✔︎ | | @aws-sdk/client-sfn | | ✔︎ | ✔︎ | | @aws-sdk/client-sns | | ✔︎ | ✔︎ | | @aws-sdk/client-sqs | | ✔︎ | ✔︎ | | Business applications | no-sdk | std-sdk | full-sdk | | --------------------- | ------ | ------- | -------- | | @aws-sdk/client-ses | | ✔︎ | ✔︎ | | @aws-sdk/client-sesv2 | | | ✔︎ | | Compute services | no-sdk | std-sdk | full-sdk | | ---------------------------- | ------ | ------- | -------- | | @aws-sdk/client-auto-scaling | | | ✔︎ | | @aws-sdk/client-batch | | | ✔︎ | | @aws-sdk/client-ec2 | | | ✔︎ | | @aws-sdk/client-lambda | | | ✔︎ | | Containers | no-sdk | std-sdk | full-sdk | | -------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-ecr | | | ✔︎ | | @aws-sdk/client-ecs | | | ✔︎ | | @aws-sdk/client-eks | | | ✔︎ | | @aws-sdk/client-servicediscovery | | | ✔︎ | | Databases | no-sdk | std-sdk | full-sdk | | -------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-dynamodb | | ✔︎ | ✔︎ | | @aws-sdk/client-dynamodb-streams | | | ✔︎ | | @aws-sdk/client-elasticache | | | ✔︎ | | @aws-sdk/client-rds | | | ✔︎ | | @aws-sdk/client-rds-data | | | ✔︎ | | Developer tools | no-sdk | std-sdk | full-sdk | | -------------------- | ------ | ------- | -------- | | @aws-sdk/client-xray | | ✔︎ | ✔︎ | | Front-end web and mobile services | no-sdk | std-sdk | full-sdk | | --------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-amplify | | | ✔︎ | | @aws-sdk/client-appsync | | | ✔︎ | | @aws-sdk/client-location | | | ✔︎ | | Machine Learning (ML) and Artificial Intelligence (AI) | no-sdk | std-sdk | full-sdk | | ------------------------------------------------------ | ------ | ------- | -------- | | @aws-sdk/client-bedrock | | | ✔︎ | | @aws-sdk/client-bedrock-runtime | | | ✔︎ | | @aws-sdk/client-bedrock-agent | | | ✔︎ | | @aws-sdk/client-bedrock-agent-runtime | | | ✔︎ | | @aws-sdk/client-polly | | | ✔︎ | | @aws-sdk/client-rekognition | | | ✔︎ | | @aws-sdk/client-textract | | | ✔︎ | | @aws-sdk/client-translate | | | ✔︎ | | Management and governance | no-sdk | std-sdk | full-sdk | | --------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-appconfig | | | ✔︎ | | @aws-sdk/client-appconfigdata | | | ✔︎ | | @aws-sdk/client-cloudformation | | | ✔︎ | | @aws-sdk/client-cloudwatch | | | ✔︎ | | @aws-sdk/client-cloudwatch-events | | ✔︎ | ✔︎ | | @aws-sdk/client-cloudwatch-logs | | ✔︎ | ✔︎ | | @aws-sdk/client-service-catalog | | | ✔︎ | | @aws-sdk/client-ssm | | ✔︎ | ✔︎ | | Media | no-sdk | std-sdk | full-sdk | | ---------------------------- | ------ | ------- | -------- | | @aws-sdk/client-mediaconvert | | | ✔︎ | | Networking and content delivery | no-sdk | std-sdk | full-sdk | | ----------------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-api-gateway | | | ✔︎ | | @aws-sdk/client-apigatewayv2 | | | ✔︎ | | @aws-sdk/client-elastic-load-balancing-v2 | | | ✔︎ | | Security, identity, and compliance | no-sdk | std-sdk | full-sdk | | ----------------------------------------- | ------ | ------- | -------- | | @aws-sdk/client-acm | | | ✔︎ | | @aws-sdk/client-cognito-identity | | ✔︎ | ✔︎ | | @aws-sdk/client-cognito-identity-provider | | ✔︎ | ✔︎ | | @aws-sdk/client-iam | | | ✔︎ | | @aws-sdk/client-kms | | ✔︎ | ✔︎ | | @aws-sdk/client-secrets-manager | | ✔︎ | ✔︎ | | @aws-sdk/client-sso | | | ✔︎ | | @aws-sdk/client-sso-admin | | | ✔︎ | | @aws-sdk/client-sso-oidc | | | ✔︎ | | @aws-sdk/client-sts | | ✔︎ | ✔︎ | | @aws-sdk/client-verifiedpermissions | | | ✔︎ | | Storage | no-sdk | std-sdk | full-sdk | | ------------------- | ------ | ------- | -------- | | @aws-sdk/client-efs | | | ✔︎ | | @aws-sdk/client-s3 | | ✔︎ | ✔︎ | | Other bundled packages | no-sdk | std-sdk | full-sdk | | -------------------------------- | ------ | ------- | -------- | | @aws-crypto | | ✔︎ | ✔︎ | | @aws-sdk/credential-providers | | ✔︎ | ✔︎ | | @aws-sdk/lib-dynamodb | | ✔︎ | ✔︎ | | @aws-sdk/lib-storage | | ✔︎ | ✔︎ | | @aws-sdk/s3-presigned-post | | ✔︎ | ✔︎ | | @aws-sdk/s3-request-presigner | | ✔︎ | ✔︎ | | @aws-sdk/util-dynamodb | | ✔︎ | ✔︎ | | @aws-sdk/util-user-agent-browser | | ✔︎ | ✔︎ | | @smithy | | ✔︎ | ✔︎ | > [!IMPORTANT] > LLRT currently does not support returning streams from SDK responses. Use `response.Body.transformToString();` or `response.Body.transformToByteArray();` as shown below. > > ```javascript > const response = await client.send(command); > // or 'transformToByteArray()' > const str = await response.Body.transformToString(); > ``` ## Running TypeScript with LLRT Same principle as dependencies applies when using TypeScript. TypeScript must be bundled and transpiled into ES2023 JavaScript. > [!NOTE] > LLRT will not support running TypeScript without transpilation. This is by design for performance reasons. Transpiling requires CPU and memory that adds latency and cost during execution. This can be avoided if done ahead of time during deployment. ## Rationale What justifies the introduction of another JavaScript runtime in light of existing options such as [Node.js](https://nodejs.org/en), [Bun](https://bun.sh) & [Deno](https://deno.com/)? Node.js, Bun, and Deno represent highly proficient JavaScript runtimes. However, they are designed with general-purpose applications in mind. These runtimes were not specifically tailored for the demands of a Serverless environment, characterized by short-lived runtime instances. They each depend on a ([Just-In-Time compiler (JIT)](https://en.wikipedia.org/wiki/Just-in-time_compilation) for dynamic code compilation and optimization during execution. While JIT compilation offers substantial long-term performance advantages, it carries a computational and memory overhead. In contrast, LLRT distinguishes itself by not incorporating a JIT compiler, a strategic decision that yields two significant advantages: A) JIT compilation is a notably sophisticated technological component, introducing increased system complexity and contributing substantially to the runtime's overall size. B) Without the JIT overhead, LLRT conserves both CPU and memory resources that can be more efficiently allocated to code execution tasks, thereby reducing application startup times. ## Limitations There are many cases where LLRT shows notable performance drawbacks compared with JIT-powered runtimes, such as large data processing, Monte Carlo simulations or performing tasks with hundreds of thousands or millions of iterations. LLRT is most effective when applied to smaller Serverless functions dedicated to tasks such as data transformation, real time processing, AWS service integrations, authorization, validation etc. It is designed to complement existing components rather than serve as a comprehensive replacement for everything. Notably, given its supported APIs are based on Node.js specification, transitioning back to alternative solutions requires minimal code adjustments. ## Building from source 1. Clone code and cd to directory ``` git clone git@github.com:awslabs/llrt.git cd llrt ``` 2. Install git submodules ``` git submodule update --init --checkout ``` 3. Install rust ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y source "$HOME/.cargo/env" ``` 4. Install dependencies ``` # MacOS brew install zig make cmake zstd node corepack # Ubuntu sudo apt -y install make zstd sudo snap install zig --classic --beta # Windows WSL2 (requires systemd to be enabled*) sudo apt -y install cmake g++ gcc make zip zstd sudo snap install zig --classic --beta # Windows WSL2 (If Node.js is not yet installed) sudo curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash nvm install --lts ``` _\* See [Microsoft Devblogs](https://devblogs.microsoft.com/commandline/systemd-support-is-now-available-in-wsl/#how-can-you-get-systemd-on-your-machine)_ 5. Install Node.js packages ``` corepack enable yarn ``` 6. Install generate libs and setup rust targets & toolchains ``` make stdlib && make libs ``` > [!NOTE] > If these commands exit with an error that says `can't cd to zstd/lib`, > you've not cloned this repository recursively. Run `git submodule update --init` to download the submodules and run the commands above again. 7. Build binaries for Lambda (Per bundle type and architecture desired) ``` # for arm64, use make llrt-lambda-arm64.zip make llrt-lambda-arm64-no-sdk.zip make llrt-lambda-arm64-full-sdk.zip # or for x86-64, use make llrt-lambda-x64.zip make llrt-lambda-x64-no-sdk.zip make llrt-lambda-x64-full-sdk.zip ``` 8. Build binaries for Container (Per bundle type and architecture desired) ``` # for arm64, use make llrt-container-arm64 make llrt-container-arm64-no-sdk make llrt-container-arm64-full-sdk # or for x86-64, use make llrt-container-x64 make llrt-container-x64-no-sdk make llrt-container-x64-full-sdk ``` 9. Optionally build for your local machine (Mac or Linux) ``` make release make release-no-sdk make release-full-sdk ``` You should now have a `llrt-lambda-arm64*.zip` or `llrt-lambda-x64*.zip`. You can manually upload this as a Lambda layer or use it via your Infrastructure-as-code pipeline ## Running Lambda emulator Please note that in order to run the example you will need: - Valid AWS credentials via a `~/.aws/credentials` or via environment variables. ```bash export AWS_ACCESS_KEY_ID=XXX export AWS_SECRET_ACCESS_KEY=YYY export AWS_REGION=us-east-1 ``` - A DynamoDB table (with `id` as the partition key) on `us-east-1` - The `dynamodb:PutItem` IAM permission on this table. You can use this policy (don't forget to modify