@temporalio/lambda-worker 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/lib/config.d.ts +12 -0
- package/lib/config.js +69 -0
- package/lib/config.js.map +1 -0
- package/lib/defaults.d.ts +16 -0
- package/lib/defaults.js +29 -0
- package/lib/defaults.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/json-logger.d.ts +29 -0
- package/lib/json-logger.js +65 -0
- package/lib/json-logger.js.map +1 -0
- package/lib/lambda-worker.d.ts +51 -0
- package/lib/lambda-worker.js +141 -0
- package/lib/lambda-worker.js.map +1 -0
- package/lib/logger-factory.d.ts +10 -0
- package/lib/logger-factory.js +28 -0
- package/lib/logger-factory.js.map +1 -0
- package/lib/otel.d.ts +83 -0
- package/lib/otel.js +103 -0
- package/lib/otel.js.map +1 -0
- package/lib/types.d.ts +70 -0
- package/lib/types.js +3 -0
- package/lib/types.js.map +1 -0
- package/package.json +86 -0
- package/src/config.ts +53 -0
- package/src/defaults.ts +30 -0
- package/src/index.ts +3 -0
- package/src/json-logger.ts +69 -0
- package/src/lambda-worker.ts +190 -0
- package/src/logger-factory.ts +27 -0
- package/src/otel.ts +127 -0
- package/src/types.ts +78 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makePowertoolsLogger = makePowertoolsLogger;
|
|
4
|
+
const json_logger_1 = require("./json-logger");
|
|
5
|
+
/**
|
|
6
|
+
* Create a Powertools-based logger for the Lambda worker.
|
|
7
|
+
*
|
|
8
|
+
* If `@aws-lambda-powertools/logger` is installed, returns a
|
|
9
|
+
* {@link PowertoolsLoggerAdapter} wrapping a Powertools Logger.
|
|
10
|
+
* Otherwise, returns `undefined`, causing the Runtime to fall back
|
|
11
|
+
* to its default logger.
|
|
12
|
+
*/
|
|
13
|
+
function makePowertoolsLogger() {
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
16
|
+
const { Logger: PtLogger } = require('@aws-lambda-powertools/logger');
|
|
17
|
+
return new json_logger_1.PowertoolsLoggerAdapter(new PtLogger({
|
|
18
|
+
serviceName: process.env['AWS_LAMBDA_FUNCTION_NAME'] ?? 'temporal-lambda-worker',
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
if (err.code !== 'MODULE_NOT_FOUND') {
|
|
23
|
+
throw err;
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=logger-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger-factory.js","sourceRoot":"","sources":["../src/logger-factory.ts"],"names":[],"mappings":";;AAWA,oDAeC;AAzBD,+CAAwD;AAExD;;;;;;;GAOG;AACH,SAAgB,oBAAoB;IAClC,IAAI,CAAC;QACH,iEAAiE;QACjE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAAC;QACtE,OAAO,IAAI,qCAAuB,CAChC,IAAI,QAAQ,CAAC;YACX,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,wBAAwB;SACjF,CAAC,CACH,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC/D,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
package/lib/otel.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
2
|
+
import { OpenTelemetryPlugin } from '@temporalio/interceptors-opentelemetry';
|
|
3
|
+
import type { LambdaWorkerConfig } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Options for the batteries-included OTel setup.
|
|
6
|
+
*/
|
|
7
|
+
export interface OtelOptions {
|
|
8
|
+
/**
|
|
9
|
+
* OTLP gRPC collector endpoint for Core SDK metrics and SDK trace span export.
|
|
10
|
+
* Defaults to `OTEL_EXPORTER_OTLP_ENDPOINT` env var, then `grpc://localhost:4317`.
|
|
11
|
+
*/
|
|
12
|
+
endpoint?: string;
|
|
13
|
+
/**
|
|
14
|
+
* OTel service name. Falls back to `OTEL_SERVICE_NAME` env var,
|
|
15
|
+
* then `AWS_LAMBDA_FUNCTION_NAME`, then `'temporal-lambda-worker'`.
|
|
16
|
+
*/
|
|
17
|
+
serviceName?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Configure OpenTelemetry for a Lambda worker:
|
|
21
|
+
*
|
|
22
|
+
* - Registers Temporal SDK interceptors (`@temporalio/interceptors-opentelemetry`) for
|
|
23
|
+
* tracing Workflow, Activity, and Nexus calls via the `OpenTelemetryPlugin`.
|
|
24
|
+
* - Configures Core-side telemetry so the Temporal Rust SDK exports its own metrics
|
|
25
|
+
* (workflow/activity task latencies, poll counts, etc.) via OTLP.
|
|
26
|
+
*
|
|
27
|
+
* Node.js-side Lambda auto-instrumentation (root spans, HTTP calls, etc.) is handled
|
|
28
|
+
* by the ADOT JS Lambda layer — this function does not set up a separate `NodeSDK` or
|
|
29
|
+
* `TracerProvider` to avoid conflicting with the layer.
|
|
30
|
+
*
|
|
31
|
+
* **Required AWS setup**: attach both Lambda layers:
|
|
32
|
+
*
|
|
33
|
+
* 1. [ADOT JavaScript layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js)
|
|
34
|
+
* — auto-instruments the handler and exports Node.js-side traces.
|
|
35
|
+
* 2. [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda)
|
|
36
|
+
* (`aws-otel-collector-amd64`) — runs the OTel Collector as a Lambda extension,
|
|
37
|
+
* receiving Core SDK metrics via OTLP on `localhost:4317` and forwarding them to
|
|
38
|
+
* CloudWatch/X-Ray.
|
|
39
|
+
*
|
|
40
|
+
* Then set these environment variables:
|
|
41
|
+
*
|
|
42
|
+
* - `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument`
|
|
43
|
+
* - `OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/otel-collector-config.yaml`
|
|
44
|
+
*
|
|
45
|
+
* **Important**: When pre-bundling Workflow code with `bundleWorkflowCode()`, you must
|
|
46
|
+
* pass `makeOtelPlugin()` so Workflow interceptor modules are included in the bundle.
|
|
47
|
+
* See {@link makeOtelPlugin}.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { runWorker } from '@temporalio/lambda-worker';
|
|
52
|
+
* import { applyDefaults } from '@temporalio/lambda-worker/otel';
|
|
53
|
+
*
|
|
54
|
+
* export const handler = runWorker(version, (config) => {
|
|
55
|
+
* applyDefaults(config);
|
|
56
|
+
* config.workerOptions.taskQueue = 'my-queue';
|
|
57
|
+
* // ...
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function applyDefaults(config: LambdaWorkerConfig, options?: OtelOptions): void;
|
|
62
|
+
/**
|
|
63
|
+
* Create the OpenTelemetry plugin for use with `Worker.create()` and
|
|
64
|
+
* `bundleWorkflowCode()`. When pre-bundling workflows, pass the returned plugin
|
|
65
|
+
* to `bundleWorkflowCode({ plugins: [plugin] })` so workflow interceptor modules
|
|
66
|
+
* are included in the bundle.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* import { bundleWorkflowCode } from '@temporalio/worker';
|
|
71
|
+
* import { makeOtelPlugin } from '@temporalio/lambda-worker/otel';
|
|
72
|
+
*
|
|
73
|
+
* const { plugin } = makeOtelPlugin();
|
|
74
|
+
* const bundle = await bundleWorkflowCode({
|
|
75
|
+
* workflowsPath: require.resolve('./workflows'),
|
|
76
|
+
* plugins: [plugin],
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function makeOtelPlugin(endpoint?: string, serviceName?: string): {
|
|
81
|
+
plugin: OpenTelemetryPlugin;
|
|
82
|
+
spanProcessor: SimpleSpanProcessor;
|
|
83
|
+
};
|
package/lib/otel.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyDefaults = applyDefaults;
|
|
4
|
+
exports.makeOtelPlugin = makeOtelPlugin;
|
|
5
|
+
const exporter_trace_otlp_grpc_1 = require("@opentelemetry/exporter-trace-otlp-grpc");
|
|
6
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
7
|
+
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
8
|
+
const interceptors_opentelemetry_1 = require("@temporalio/interceptors-opentelemetry");
|
|
9
|
+
/**
|
|
10
|
+
* Configure OpenTelemetry for a Lambda worker:
|
|
11
|
+
*
|
|
12
|
+
* - Registers Temporal SDK interceptors (`@temporalio/interceptors-opentelemetry`) for
|
|
13
|
+
* tracing Workflow, Activity, and Nexus calls via the `OpenTelemetryPlugin`.
|
|
14
|
+
* - Configures Core-side telemetry so the Temporal Rust SDK exports its own metrics
|
|
15
|
+
* (workflow/activity task latencies, poll counts, etc.) via OTLP.
|
|
16
|
+
*
|
|
17
|
+
* Node.js-side Lambda auto-instrumentation (root spans, HTTP calls, etc.) is handled
|
|
18
|
+
* by the ADOT JS Lambda layer — this function does not set up a separate `NodeSDK` or
|
|
19
|
+
* `TracerProvider` to avoid conflicting with the layer.
|
|
20
|
+
*
|
|
21
|
+
* **Required AWS setup**: attach both Lambda layers:
|
|
22
|
+
*
|
|
23
|
+
* 1. [ADOT JavaScript layer](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js)
|
|
24
|
+
* — auto-instruments the handler and exports Node.js-side traces.
|
|
25
|
+
* 2. [ADOT Collector layer](https://aws-otel.github.io/docs/getting-started/lambda)
|
|
26
|
+
* (`aws-otel-collector-amd64`) — runs the OTel Collector as a Lambda extension,
|
|
27
|
+
* receiving Core SDK metrics via OTLP on `localhost:4317` and forwarding them to
|
|
28
|
+
* CloudWatch/X-Ray.
|
|
29
|
+
*
|
|
30
|
+
* Then set these environment variables:
|
|
31
|
+
*
|
|
32
|
+
* - `AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-instrument`
|
|
33
|
+
* - `OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/otel-collector-config.yaml`
|
|
34
|
+
*
|
|
35
|
+
* **Important**: When pre-bundling Workflow code with `bundleWorkflowCode()`, you must
|
|
36
|
+
* pass `makeOtelPlugin()` so Workflow interceptor modules are included in the bundle.
|
|
37
|
+
* See {@link makeOtelPlugin}.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { runWorker } from '@temporalio/lambda-worker';
|
|
42
|
+
* import { applyDefaults } from '@temporalio/lambda-worker/otel';
|
|
43
|
+
*
|
|
44
|
+
* export const handler = runWorker(version, (config) => {
|
|
45
|
+
* applyDefaults(config);
|
|
46
|
+
* config.workerOptions.taskQueue = 'my-queue';
|
|
47
|
+
* // ...
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
function applyDefaults(config, options) {
|
|
52
|
+
const endpoint = options?.endpoint ?? process.env['OTEL_EXPORTER_OTLP_ENDPOINT'] ?? 'grpc://localhost:4317';
|
|
53
|
+
// Configure Core-side telemetry so the Temporal Rust SDK exports its own
|
|
54
|
+
// metrics (workflow/activity task latencies, poll counts, etc.) to the
|
|
55
|
+
// standalone ADOT collector extension running as a Lambda layer.
|
|
56
|
+
config.runtimeOptions.telemetryOptions = {
|
|
57
|
+
...config.runtimeOptions.telemetryOptions,
|
|
58
|
+
metrics: {
|
|
59
|
+
otel: {
|
|
60
|
+
url: endpoint,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
// Set up the OpenTelemetry plugin for Temporal SDK interceptors.
|
|
65
|
+
// This traces Workflow, Activity, and Nexus calls.
|
|
66
|
+
const { plugin, spanProcessor } = makeOtelPlugin(endpoint, options?.serviceName);
|
|
67
|
+
config.workerOptions.plugins = [...(config.workerOptions.plugins ?? []), plugin];
|
|
68
|
+
config.shutdownHooks.push(async () => {
|
|
69
|
+
await spanProcessor.forceFlush();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
// TODO: Spans don't automatically get parented to the lambda invocation span, and it's not clear
|
|
73
|
+
// how we'd make that work, but is worth doing in the future if possible.
|
|
74
|
+
/**
|
|
75
|
+
* Create the OpenTelemetry plugin for use with `Worker.create()` and
|
|
76
|
+
* `bundleWorkflowCode()`. When pre-bundling workflows, pass the returned plugin
|
|
77
|
+
* to `bundleWorkflowCode({ plugins: [plugin] })` so workflow interceptor modules
|
|
78
|
+
* are included in the bundle.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { bundleWorkflowCode } from '@temporalio/worker';
|
|
83
|
+
* import { makeOtelPlugin } from '@temporalio/lambda-worker/otel';
|
|
84
|
+
*
|
|
85
|
+
* const { plugin } = makeOtelPlugin();
|
|
86
|
+
* const bundle = await bundleWorkflowCode({
|
|
87
|
+
* workflowsPath: require.resolve('./workflows'),
|
|
88
|
+
* plugins: [plugin],
|
|
89
|
+
* });
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
function makeOtelPlugin(endpoint, serviceName) {
|
|
93
|
+
const resolvedEndpoint = endpoint ?? process.env['OTEL_EXPORTER_OTLP_ENDPOINT'] ?? 'grpc://localhost:4317';
|
|
94
|
+
const resolvedServiceName = serviceName ??
|
|
95
|
+
process.env['OTEL_SERVICE_NAME'] ??
|
|
96
|
+
process.env['AWS_LAMBDA_FUNCTION_NAME'] ??
|
|
97
|
+
'temporal-lambda-worker';
|
|
98
|
+
const resource = new resources_1.Resource({ 'service.name': resolvedServiceName });
|
|
99
|
+
const traceExporter = new exporter_trace_otlp_grpc_1.OTLPTraceExporter({ url: resolvedEndpoint });
|
|
100
|
+
const spanProcessor = new sdk_trace_base_1.SimpleSpanProcessor(traceExporter);
|
|
101
|
+
return { plugin: new interceptors_opentelemetry_1.OpenTelemetryPlugin({ resource, spanProcessor }), spanProcessor };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=otel.js.map
|
package/lib/otel.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":";;AAiEA,sCAuBC;AAsBD,wCAgBC;AA9HD,sFAA4E;AAC5E,wDAAoD;AACpD,kEAAoE;AACpE,uFAA6E;AAoB7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,SAAgB,aAAa,CAAC,MAA0B,EAAE,OAAqB;IAC7E,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,IAAI,uBAAuB,CAAC;IAE5G,yEAAyE;IACzE,uEAAuE;IACvE,iEAAiE;IACjE,MAAM,CAAC,cAAc,CAAC,gBAAgB,GAAG;QACvC,GAAG,MAAM,CAAC,cAAc,CAAC,gBAAgB;QACzC,OAAO,EAAE;YACP,IAAI,EAAE;gBACJ,GAAG,EAAE,QAAQ;aACd;SACF;KACF,CAAC;IAEF,iEAAiE;IACjE,mDAAmD;IACnD,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IACjF,MAAM,CAAC,aAAa,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IAEjF,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;QACnC,MAAM,aAAa,CAAC,UAAU,EAAE,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iGAAiG;AACjG,yEAAyE;AACzE;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,cAAc,CAC5B,QAAiB,EACjB,WAAoB;IAEpB,MAAM,gBAAgB,GAAG,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,IAAI,uBAAuB,CAAC;IAC3G,MAAM,mBAAmB,GACvB,WAAW;QACX,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;QACvC,wBAAwB,CAAC;IAE3B,MAAM,QAAQ,GAAG,IAAI,oBAAQ,CAAC,EAAE,cAAc,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,IAAI,4CAAiB,CAAC,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,IAAI,oCAAmB,CAAC,aAAa,CAAC,CAAC;IAE7D,OAAO,EAAE,MAAM,EAAE,IAAI,gDAAmB,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC;AACzF,CAAC"}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Context } from 'aws-lambda';
|
|
2
|
+
import type { VersioningBehavior } from '@temporalio/common';
|
|
3
|
+
import type { WorkerOptions, NativeConnectionOptions, RuntimeOptions } from '@temporalio/worker';
|
|
4
|
+
/**
|
|
5
|
+
* A function called after the worker stops on each invocation.
|
|
6
|
+
* Errors are caught, logged, and do not prevent subsequent hooks from running.
|
|
7
|
+
*/
|
|
8
|
+
export type ShutdownHook = () => Promise<void> | void;
|
|
9
|
+
/**
|
|
10
|
+
* Configuration object passed to the {@link runWorker} configure callback.
|
|
11
|
+
*
|
|
12
|
+
* Pre-populated with Lambda-tuned defaults. You should set `workerOptions.taskQueue`, register
|
|
13
|
+
* activities/workflows, and override any defaults as needed.
|
|
14
|
+
*/
|
|
15
|
+
export interface LambdaWorkerConfig {
|
|
16
|
+
/**
|
|
17
|
+
* Worker options, pre-populated with Lambda-appropriate defaults.
|
|
18
|
+
*
|
|
19
|
+
* You must set at least `taskQueue` (or set the `TEMPORAL_TASK_QUEUE` env var). Typically you'll
|
|
20
|
+
* also set `activities` and `workflowBundle` (prefer pre-bundled workflows over `workflowsPath`
|
|
21
|
+
* to avoid bundling overhead on Lambda cold starts).
|
|
22
|
+
*
|
|
23
|
+
* The following fields are managed by settings elsewhere and will be overridden per-invocation:
|
|
24
|
+
* `connection`, `namespace`, `identity`.
|
|
25
|
+
*/
|
|
26
|
+
workerOptions: Partial<Omit<WorkerOptions, 'connection' | 'namespace' | 'identity' | 'workerDeploymentOptions'>> & {
|
|
27
|
+
/**
|
|
28
|
+
* `version` and `useWorkerVersioning` are managed by `runWorker` and cannot be set here.
|
|
29
|
+
*
|
|
30
|
+
* @default { defaultVersioningBehavior: 'PINNED' }
|
|
31
|
+
*/
|
|
32
|
+
workerDeploymentOptions?: {
|
|
33
|
+
defaultVersioningBehavior?: VersioningBehavior;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Connection options overrides, merged on top of values loaded via envconfig.
|
|
38
|
+
*/
|
|
39
|
+
connectionOptions?: Partial<NativeConnectionOptions>;
|
|
40
|
+
/**
|
|
41
|
+
* Namespace override. Falls back to the envconfig-loaded value, then `"default"`.
|
|
42
|
+
*/
|
|
43
|
+
namespace?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Time in milliseconds before the Lambda invocation deadline at which the worker
|
|
46
|
+
* begins its shutdown sequence (graceful drain + shutdown hooks).
|
|
47
|
+
*
|
|
48
|
+
* @default 7000 (5s graceful shutdown + 2s margin)
|
|
49
|
+
*/
|
|
50
|
+
shutdownDeadlineBufferMs?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Options for the Temporal {@link Runtime} singleton, installed automatically by `runWorker`.
|
|
53
|
+
*
|
|
54
|
+
* Pre-populated with a Powertools JSON logger (if `@aws-lambda-powertools/logger` is installed)
|
|
55
|
+
* and `shutdownSignals: []` (Lambda manages its own lifecycle).
|
|
56
|
+
*
|
|
57
|
+
* Override `runtimeOptions.logger` to use a custom logger, or modify `runtimeOptions.telemetryOptions`
|
|
58
|
+
* to configure Core-side telemetry.
|
|
59
|
+
*/
|
|
60
|
+
runtimeOptions: RuntimeOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Hooks executed in order after the worker stops on each invocation.
|
|
63
|
+
* Each hook's errors are caught and logged without preventing subsequent hooks.
|
|
64
|
+
*/
|
|
65
|
+
shutdownHooks: ShutdownHook[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The Lambda handler function returned by {@link runWorker}.
|
|
69
|
+
*/
|
|
70
|
+
export type LambdaHandler = (event: unknown, context: Context) => Promise<void>;
|
package/lib/types.js
ADDED
package/lib/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@temporalio/lambda-worker",
|
|
3
|
+
"version": "1.17.0",
|
|
4
|
+
"description": "Temporal.io SDK AWS Lambda Worker",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "./lib/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./lib/index.d.ts",
|
|
10
|
+
"default": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./otel": {
|
|
13
|
+
"types": "./lib/otel.d.ts",
|
|
14
|
+
"default": "./lib/otel.js"
|
|
15
|
+
},
|
|
16
|
+
"./lib/*": {
|
|
17
|
+
"types": "./lib/*.d.ts",
|
|
18
|
+
"default": "./lib/*.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"temporal",
|
|
23
|
+
"aws",
|
|
24
|
+
"lambda",
|
|
25
|
+
"worker"
|
|
26
|
+
],
|
|
27
|
+
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@temporalio/common": "1.17.0",
|
|
31
|
+
"@temporalio/envconfig": "1.17.0",
|
|
32
|
+
"@temporalio/worker": "1.17.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@aws-lambda-powertools/logger": "^2.0.0",
|
|
36
|
+
"@types/aws-lambda": "^8.10.145"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@aws-lambda-powertools/logger": "^2.0.0",
|
|
40
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.52.0",
|
|
41
|
+
"@opentelemetry/resources": "^1.25.1",
|
|
42
|
+
"@opentelemetry/sdk-trace-base": "^1.25.1",
|
|
43
|
+
"@types/aws-lambda": "^8.10.145",
|
|
44
|
+
"@temporalio/interceptors-opentelemetry": "1.17.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"@aws-lambda-powertools/logger": {
|
|
48
|
+
"optional": true
|
|
49
|
+
},
|
|
50
|
+
"@temporalio/interceptors-opentelemetry": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"@opentelemetry/exporter-trace-otlp-grpc": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"@opentelemetry/resources": {
|
|
57
|
+
"optional": true
|
|
58
|
+
},
|
|
59
|
+
"@opentelemetry/sdk-trace-base": {
|
|
60
|
+
"optional": true
|
|
61
|
+
},
|
|
62
|
+
"@types/aws-lambda": {
|
|
63
|
+
"optional": true
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">= 20.0.0"
|
|
68
|
+
},
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/temporalio/sdk-typescript/issues"
|
|
71
|
+
},
|
|
72
|
+
"repository": {
|
|
73
|
+
"type": "git",
|
|
74
|
+
"url": "git+https://github.com/temporalio/sdk-typescript.git",
|
|
75
|
+
"directory": "packages/lambda-worker"
|
|
76
|
+
},
|
|
77
|
+
"homepage": "https://github.com/temporalio/sdk-typescript/tree/main/packages/lambda-worker",
|
|
78
|
+
"publishConfig": {
|
|
79
|
+
"access": "public"
|
|
80
|
+
},
|
|
81
|
+
"files": [
|
|
82
|
+
"src",
|
|
83
|
+
"lib"
|
|
84
|
+
],
|
|
85
|
+
"scripts": {}
|
|
86
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import {
|
|
4
|
+
type ClientConnectConfig,
|
|
5
|
+
type LoadClientProfileOptions,
|
|
6
|
+
loadClientConnectConfig,
|
|
7
|
+
} from '@temporalio/envconfig';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Load client connection config with Lambda-aware config file resolution.
|
|
11
|
+
*
|
|
12
|
+
* Resolution order:
|
|
13
|
+
* 1. User-provided `configSource` in options (passthrough)
|
|
14
|
+
* 2. `TEMPORAL_CONFIG_FILE` env var (handled by envconfig)
|
|
15
|
+
* 3. `$LAMBDA_TASK_ROOT/temporal.toml`
|
|
16
|
+
* 4. `process.cwd()/temporal.toml`
|
|
17
|
+
* 5. Envconfig default (XDG paths / env-only)
|
|
18
|
+
*/
|
|
19
|
+
export function loadLambdaClientConnectConfig(options?: Partial<LoadClientProfileOptions>): ClientConnectConfig {
|
|
20
|
+
const resolvedOptions: LoadClientProfileOptions = { ...options };
|
|
21
|
+
|
|
22
|
+
// If the user provided a configSource or TEMPORAL_CONFIG_FILE is set, let envconfig handle it
|
|
23
|
+
if (!resolvedOptions.configSource && !process.env['TEMPORAL_CONFIG_FILE']) {
|
|
24
|
+
const lambdaConfigPath = findLambdaConfigFile();
|
|
25
|
+
if (lambdaConfigPath) {
|
|
26
|
+
resolvedOptions.configSource = { path: lambdaConfigPath };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return loadClientConnectConfig(resolvedOptions);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function findLambdaConfigFile(): string | undefined {
|
|
34
|
+
const candidates: string[] = [];
|
|
35
|
+
|
|
36
|
+
const lambdaTaskRoot = process.env['LAMBDA_TASK_ROOT'];
|
|
37
|
+
if (lambdaTaskRoot) {
|
|
38
|
+
candidates.push(path.join(lambdaTaskRoot, 'temporal.toml'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
candidates.push(path.join(process.cwd(), 'temporal.toml'));
|
|
42
|
+
|
|
43
|
+
for (const candidate of candidates) {
|
|
44
|
+
try {
|
|
45
|
+
fs.accessSync(candidate, fs.constants.R_OK);
|
|
46
|
+
return candidate;
|
|
47
|
+
} catch {
|
|
48
|
+
// File doesn't exist or isn't readable, try next
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
package/src/defaults.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { WorkerOptions } from '@temporalio/worker';
|
|
2
|
+
|
|
3
|
+
/** Minimum work time in ms — error if less. */
|
|
4
|
+
export const MINIMUM_WORK_TIME_MS = 1000;
|
|
5
|
+
|
|
6
|
+
/** Low work time threshold in ms — warn if less. */
|
|
7
|
+
export const WARN_WORK_TIME_MS = 5000;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default buffer in ms before the Lambda deadline to begin shutdown.
|
|
11
|
+
* Equals the default shutdownGraceTime (5s) + 2s margin.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_SHUTDOWN_DEADLINE_BUFFER_MS = 7000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Lambda-tuned worker defaults. These are conservative values appropriate for
|
|
17
|
+
* Lambda's memory and CPU constraints. Users can override any of these via the
|
|
18
|
+
* configure callback.
|
|
19
|
+
*/
|
|
20
|
+
export const LAMBDA_WORKER_DEFAULTS: Partial<WorkerOptions> = {
|
|
21
|
+
maxConcurrentActivityTaskExecutions: 2,
|
|
22
|
+
maxConcurrentWorkflowTaskExecutions: 10,
|
|
23
|
+
maxConcurrentLocalActivityExecutions: 2,
|
|
24
|
+
maxConcurrentNexusTaskExecutions: 5,
|
|
25
|
+
shutdownGraceTime: '5s',
|
|
26
|
+
maxCachedWorkflows: 30,
|
|
27
|
+
workflowTaskPollerBehavior: { type: 'simple-maximum', maximum: 2 },
|
|
28
|
+
activityTaskPollerBehavior: { type: 'simple-maximum', maximum: 1 },
|
|
29
|
+
nexusTaskPollerBehavior: { type: 'simple-maximum', maximum: 1 },
|
|
30
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Logger as PowertoolsLogger } from '@aws-lambda-powertools/logger';
|
|
2
|
+
import type { Context } from 'aws-lambda';
|
|
3
|
+
import type { LogLevel, LogMetadata } from '@temporalio/common';
|
|
4
|
+
import type { Logger } from '@temporalio/worker';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Adapter that wraps an AWS Lambda Powertools Logger to implement the Temporal SDK Logger interface.
|
|
8
|
+
*
|
|
9
|
+
* This is used as the default logger for the Lambda worker, producing structured JSON output
|
|
10
|
+
* that CloudWatch Logs automatically parses.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { Logger } from '@aws-lambda-powertools/logger';
|
|
15
|
+
* import { PowertoolsLoggerAdapter } from '@temporalio/lambda-worker';
|
|
16
|
+
*
|
|
17
|
+
* const adapter = new PowertoolsLoggerAdapter(new Logger({ serviceName: 'my-worker' }));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export class PowertoolsLoggerAdapter implements Logger {
|
|
21
|
+
constructor(private readonly ptLogger: PowertoolsLogger) {}
|
|
22
|
+
|
|
23
|
+
addContext(context: Context): void {
|
|
24
|
+
this.ptLogger.addContext(context);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
log(level: LogLevel, message: string, meta?: LogMetadata): void {
|
|
28
|
+
switch (level) {
|
|
29
|
+
case 'TRACE':
|
|
30
|
+
this.ptLogger.debug(message, { ...meta, traceLevel: true });
|
|
31
|
+
break;
|
|
32
|
+
case 'DEBUG':
|
|
33
|
+
this.ptLogger.debug(message, meta as Record<string, unknown>);
|
|
34
|
+
break;
|
|
35
|
+
case 'INFO':
|
|
36
|
+
this.ptLogger.info(message, meta as Record<string, unknown>);
|
|
37
|
+
break;
|
|
38
|
+
case 'WARN':
|
|
39
|
+
this.ptLogger.warn(message, meta as Record<string, unknown>);
|
|
40
|
+
break;
|
|
41
|
+
case 'ERROR':
|
|
42
|
+
this.ptLogger.error(message, meta as Record<string, unknown>);
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
level satisfies never;
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
trace(message: string, meta?: LogMetadata): void {
|
|
51
|
+
this.log('TRACE', message, meta);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
debug(message: string, meta?: LogMetadata): void {
|
|
55
|
+
this.log('DEBUG', message, meta);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
info(message: string, meta?: LogMetadata): void {
|
|
59
|
+
this.log('INFO', message, meta);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
warn(message: string, meta?: LogMetadata): void {
|
|
63
|
+
this.log('WARN', message, meta);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
error(message: string, meta?: LogMetadata): void {
|
|
67
|
+
this.log('ERROR', message, meta);
|
|
68
|
+
}
|
|
69
|
+
}
|