-
Notifications
You must be signed in to change notification settings - Fork 147
Introduce lambda worker sample #455
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
Draft
Sushisource
wants to merge
1
commit into
main
Choose a base branch
from
lambda-worker
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -111,3 +111,6 @@ package-lock.json | |
| */**/pnpm-lock.yaml | ||
|
|
||
| .idea/ | ||
|
|
||
| **/client.key | ||
| **/client.pem | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1 @@ | ||
| link-workspace-packages = true | ||
| prefer-workspace-packages = true | ||
| package-lock=false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| node_modules | ||
| lib | ||
| .eslintrc.js |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| const { builtinModules } = require('module'); | ||
|
|
||
| const ALLOWED_NODE_BUILTINS = new Set(['assert']); | ||
|
|
||
| module.exports = { | ||
| root: true, | ||
| parser: '@typescript-eslint/parser', | ||
| parserOptions: { | ||
| project: './tsconfig.json', | ||
| tsconfigRootDir: __dirname, | ||
| }, | ||
| plugins: ['@typescript-eslint', 'deprecation'], | ||
| extends: [ | ||
| 'eslint:recommended', | ||
| 'plugin:@typescript-eslint/eslint-recommended', | ||
| 'plugin:@typescript-eslint/recommended', | ||
| 'prettier', | ||
| ], | ||
| rules: { | ||
| // recommended for safety | ||
| '@typescript-eslint/no-floating-promises': 'error', // forgetting to await Activities and Workflow APIs is bad | ||
| 'deprecation/deprecation': 'warn', | ||
|
|
||
| // code style preference | ||
| 'object-shorthand': ['error', 'always'], | ||
|
|
||
| // relaxed rules, for convenience | ||
| '@typescript-eslint/no-unused-vars': [ | ||
| 'warn', | ||
| { | ||
| argsIgnorePattern: '^_', | ||
| varsIgnorePattern: '^_', | ||
| }, | ||
| ], | ||
| '@typescript-eslint/no-explicit-any': 'off', | ||
| }, | ||
| overrides: [ | ||
| { | ||
| files: ['src/workflows.ts', 'src/workflows-*.ts', 'src/workflows/*.ts'], | ||
| rules: { | ||
| 'no-restricted-imports': [ | ||
| 'error', | ||
| ...builtinModules.filter((m) => !ALLOWED_NODE_BUILTINS.has(m)).flatMap((m) => [m, `node:${m}`]), | ||
| ], | ||
| }, | ||
| }, | ||
| ], | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| lib | ||
| node_modules | ||
| workflow-bundle.js | ||
| function.zip | ||
| package/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| package-lock=false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 22 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| lib |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| printWidth: 120 | ||
| singleQuote: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # Lambda Worker | ||
|
|
||
| This sample demonstrates how to run a Temporal Worker inside an AWS Lambda function using | ||
| the [`@temporalio/lambda-worker`](https://typescript.temporal.io) package. It includes | ||
| optional OpenTelemetry instrumentation that exports traces and metrics through AWS Distro | ||
| for OpenTelemetry (ADOT). | ||
|
|
||
| The sample registers a simple greeting Workflow and Activity, but the pattern applies to | ||
| any Workflow/Activity definitions. | ||
|
|
||
| The sample includes [`@aws-lambda-powertools/logger`](https://docs.aws.amazon.com/powertools/typescript/latest/features/logger/), | ||
| which `@temporalio/lambda-worker` automatically detects and uses to produce structured JSON | ||
| logs that CloudWatch Logs can parse natively. If you don't need structured logging, you can | ||
| remove the dependency and the SDK will fall back to its default human-readable logger. | ||
|
|
||
| > **Note:** `@temporalio/lambda-worker` is not yet published. The `package.json` currently | ||
| > references it via a local `file:` path to `../../sdk-node/packages/lambda-worker`. | ||
| > TODO: Replace with a versioned dependency (e.g. `^1.15.0`) once the package is published. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - A [Temporal Cloud](https://temporal.io/cloud) namespace (or a self-hosted Temporal | ||
| cluster accessible from your Lambda) | ||
| - AWS CLI configured with permissions to create Lambda functions, IAM roles, and | ||
| CloudFormation stacks | ||
| - mTLS client certificate and key for your Temporal namespace (place as `client.pem` and | ||
| `client.key` in this directory) | ||
| - Node.js 22+ | ||
|
|
||
| ## Files | ||
|
|
||
| | File | Description | | ||
| | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | ||
| | `src/index.ts` | Lambda entry point — configures the worker, registers Workflows/Activities, enables OTel, and exports the handler | | ||
| | `src/workflows.ts` | Sample Workflow that executes a greeting Activity | | ||
| | `src/activities.ts` | Sample Activity that returns a greeting string | | ||
| | `src/client.ts` | Helper program to start a Workflow execution from a local machine | | ||
| | `src/scripts/build-workflow-bundle.ts` | Pre-bundles Workflow code with OTel interceptor modules for Lambda cold start performance | | ||
| | `temporal.toml` | Temporal client connection configuration (update with your namespace) | | ||
| | `otel-collector-config.yaml` | OpenTelemetry Collector configuration for ADOT (routes metrics to CloudWatch, traces to X-Ray) | | ||
| | `deploy-lambda.sh` | Packages and deploys the Lambda function | | ||
| | `mk-iam-role.sh` | Creates the IAM role that allows Temporal Cloud to invoke the Lambda | | ||
| | `iam-role-for-temporal-lambda-invoke-test.yaml` | CloudFormation template for the IAM role | | ||
| | `extra-setup-steps` | Additional IAM and Lambda configuration for OpenTelemetry support | | ||
|
|
||
| ## Setup | ||
|
|
||
| ### 1. Configure Temporal connection | ||
|
|
||
| Edit `temporal.toml` with your Temporal Cloud namespace address and credentials. In production, | ||
| we'd recommend reading your credentials from a secret store, but to keep this example simple | ||
| the toml file defaults to reading them from keys bundled along with the Lambda code. | ||
|
|
||
| ### 2. Create the IAM role | ||
|
|
||
| This creates the IAM role that Temporal Cloud assumes to invoke your Lambda function: | ||
|
|
||
| ```bash | ||
| ./mk-iam-role.sh <stack-name> <external-id> <lambda-arn> | ||
| ``` | ||
|
|
||
| The External ID is provided by Temporal Cloud in your namespace's serverless worker | ||
| configuration. | ||
|
|
||
| ### 3. (Optional) Enable OpenTelemetry | ||
|
|
||
| The sample calls `applyDefaults(config)` in the handler, which registers Temporal SDK | ||
| interceptors for tracing Workflow, Activity, and Nexus calls, and configures the Core SDK | ||
| to export metrics via OTLP. To complete the setup, attach two ADOT Lambda layers: | ||
|
|
||
| 1. **ADOT JavaScript layer** — auto-instruments the handler and exports Node.js-side | ||
| traces to X-Ray. See [this page](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js) | ||
| for the layer ARN for your region. | ||
| 2. **ADOT Collector layer** (`aws-otel-collector-amd64`) — runs the OTel Collector as a | ||
| Lambda extension, receiving Temporal Core SDK metrics via OTLP and forwarding them to | ||
| CloudWatch/X-Ray. See [this page](https://aws-otel.github.io/docs/getting-started/lambda) | ||
| for the layer ARN. | ||
|
|
||
| Update `otel-collector-config.yaml` with your function name and region, then set the | ||
| following environment variables on your Lambda: | ||
|
|
||
| ``` | ||
| AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument | ||
| OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/otel-collector-config.yaml | ||
| ``` | ||
|
|
||
| `AWS_LAMBDA_EXEC_WRAPPER` enables the JS layer's auto-instrumentation. | ||
| `OPENTELEMETRY_COLLECTOR_CONFIG_URI` points the collector at the custom config that | ||
| routes metrics to CloudWatch EMF and traces to X-Ray. | ||
|
|
||
| Enable X-Ray active tracing on the Lambda function (required for traces to appear): | ||
|
|
||
| ```bash | ||
| aws lambda update-function-configuration --function-name <function-name> \ | ||
| --tracing-config Mode=Active | ||
| ``` | ||
|
|
||
| Then run the extra setup to grant the Lambda role the necessary permissions: | ||
|
|
||
| ```bash | ||
| ./extra-setup-steps <role-name> <function-name> <region> <account-id> | ||
| ``` | ||
|
|
||
| ### 4. Deploy the Lambda function | ||
|
|
||
| Create a Lambda function in AWS with: | ||
|
|
||
| - **Runtime**: Node.js >=20 | ||
| - **Handler**: `index.handler` (the default) | ||
| - **Architecture**: x86_64 | ||
|
|
||
| It's likely you will need to increase the default memory limit in AWS for your lambda. A minimum of | ||
| 256MB is recommended. | ||
|
|
||
| Then deploy: | ||
|
|
||
| ```bash | ||
| ./deploy-lambda.sh <function-name> | ||
| ``` | ||
|
|
||
| This compiles TypeScript, pre-bundles Workflow code, packages everything with dependencies, | ||
| and uploads to AWS Lambda. | ||
|
|
||
| ### 5. Start a Workflow | ||
|
|
||
| Use the starter program to execute a Workflow on the Lambda worker, using | ||
| the same config file the Lambda uses for connecting to the server: | ||
|
|
||
| ```bash | ||
| TEMPORAL_CONFIG_FILE=temporal.toml pnpm workflow | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
|
|
||
| FUNCTION_NAME="${1:?Usage: deploy-lambda.sh <function-name>}" | ||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| SDK_DIR="$SCRIPT_DIR/../../sdk-node" | ||
|
|
||
| # Build TypeScript | ||
| cd "$SCRIPT_DIR" | ||
| pnpm build | ||
|
|
||
| # Bundle workflows | ||
| pnpm build:workflow-bundle | ||
|
|
||
| # Create packaging directory | ||
| rm -rf "$SCRIPT_DIR/package" | ||
| mkdir -p "$SCRIPT_DIR/package" | ||
|
|
||
| # Copy compiled JS to package root (so index.js is at zip root for the default handler) | ||
| cp "$SCRIPT_DIR/lib/"*.js "$SCRIPT_DIR/package/" | ||
|
|
||
| # Copy workflow bundle alongside the handler | ||
| cp "$SCRIPT_DIR/workflow-bundle.js" "$SCRIPT_DIR/package/" | ||
|
|
||
| # Install production dependencies. | ||
| # TODO: Once @temporalio/lambda-worker is published, remove the sed and the | ||
| # manual copy below — npm install will handle everything. | ||
| cd "$SCRIPT_DIR/package" | ||
| sed '/@temporalio\/lambda-worker/d' "$SCRIPT_DIR/package.json" > package.json | ||
| npm install --omit=dev --ignore-scripts | ||
|
|
||
| # Strip native binaries for platforms other than Lambda's (linux x86_64) | ||
| find node_modules/@temporalio/core-bridge/releases -mindepth 1 -maxdepth 1 \ | ||
| ! -name 'x86_64-unknown-linux-gnu' -exec rm -rf {} + | ||
|
|
||
| # Manually place the local lambda-worker package (not yet published) | ||
| mkdir -p node_modules/@temporalio/lambda-worker | ||
| cp "$SDK_DIR/packages/lambda-worker/package.json" node_modules/@temporalio/lambda-worker/ | ||
| cp -r "$SDK_DIR/packages/lambda-worker/lib" node_modules/@temporalio/lambda-worker/ | ||
|
|
||
| # Copy config files and certs | ||
| cp "$SCRIPT_DIR/temporal.toml" "$SCRIPT_DIR/otel-collector-config.yaml" \ | ||
| "$SCRIPT_DIR/client.pem" "$SCRIPT_DIR/client.key" "$SCRIPT_DIR/package/" | ||
|
|
||
| # Create zip | ||
| cd "$SCRIPT_DIR/package" | ||
| zip -r "$SCRIPT_DIR/function.zip" . | ||
|
|
||
| # Deploy | ||
| aws lambda update-function-code --function-name "$FUNCTION_NAME" \ | ||
| --zip-file fileb://"$SCRIPT_DIR/function.zip" | ||
|
|
||
| # Cleanup | ||
| rm -rf "$SCRIPT_DIR/package" "$SCRIPT_DIR/function.zip" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
|
|
||
| # Additional setup steps for OpenTelemetry support. | ||
| # These are needed if you want metrics, logs, and traces from your Lambda worker. | ||
|
|
||
| ROLE_NAME="${1:?Usage: extra-setup-steps <role-name> <function-name> <region> <account-id>}" | ||
| FUNCTION_NAME="${2:?Usage: extra-setup-steps <role-name> <function-name> <region> <account-id>}" | ||
| REGION="${3:?Usage: extra-setup-steps <role-name> <function-name> <region> <account-id>}" | ||
| ACCOUNT_ID="${4:?Usage: extra-setup-steps <role-name> <function-name> <region> <account-id>}" | ||
|
|
||
| # Needed to allow metrics/logs/traces to be published | ||
| aws iam put-role-policy \ | ||
| --role-name "$ROLE_NAME" \ | ||
| --policy-name ADOT-Telemetry-Permissions \ | ||
| --policy-document "{ | ||
| \"Version\": \"2012-10-17\", | ||
| \"Statement\": [ | ||
| { | ||
| \"Effect\": \"Allow\", | ||
| \"Action\": [ | ||
| \"logs:CreateLogGroup\", | ||
| \"logs:CreateLogStream\", | ||
| \"logs:PutLogEvents\" | ||
| ], | ||
| \"Resource\": \"arn:aws:logs:${REGION}:${ACCOUNT_ID}:log-group:/aws/lambda/${FUNCTION_NAME}:*\" | ||
| }, | ||
| { | ||
| \"Effect\": \"Allow\", | ||
| \"Action\": [ | ||
| \"xray:PutTraceSegments\", | ||
| \"xray:PutTelemetryRecords\" | ||
| ], | ||
| \"Resource\": \"*\" | ||
| }, | ||
| { | ||
| \"Effect\": \"Allow\", | ||
| \"Action\": [ | ||
| \"cloudwatch:PutMetricData\" | ||
| ], | ||
| \"Resource\": \"*\" | ||
| } | ||
| ] | ||
| }" | ||
|
|
||
| # Needed to make traces show up with type: `"AWS::Lambda::Function"` filter | ||
| aws lambda update-function-configuration \ | ||
| --function-name "$FUNCTION_NAME" --tracing-config Mode=Active |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be
otel-handler.otel-instrumentseems to be for Python, not Node.js