@composurecdk/lambda 0.8.4 → 0.8.6
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/README.md +67 -16
- package/dist/commonjs/alarm-config.d.ts +22 -0
- package/dist/commonjs/alarm-config.d.ts.map +1 -1
- package/dist/commonjs/alarm-defaults.d.ts +1 -0
- package/dist/commonjs/alarm-defaults.d.ts.map +1 -1
- package/dist/commonjs/alarm-defaults.js +15 -0
- package/dist/commonjs/alarm-defaults.js.map +1 -1
- package/dist/commonjs/event-sources/composure-event-source.d.ts +4 -4
- package/dist/commonjs/event-sources/composure-event-source.d.ts.map +1 -1
- package/dist/commonjs/event-sources/composure-event-source.js +7 -3
- package/dist/commonjs/event-sources/composure-event-source.js.map +1 -1
- package/dist/commonjs/event-sources/dynamodb-event-source.d.ts +55 -0
- package/dist/commonjs/event-sources/dynamodb-event-source.d.ts.map +1 -0
- package/dist/commonjs/event-sources/dynamodb-event-source.js +88 -0
- package/dist/commonjs/event-sources/dynamodb-event-source.js.map +1 -0
- package/dist/commonjs/event-sources/event-source-relationship-guards.d.ts +28 -0
- package/dist/commonjs/event-sources/event-source-relationship-guards.d.ts.map +1 -0
- package/dist/commonjs/event-sources/event-source-relationship-guards.js +105 -0
- package/dist/commonjs/event-sources/event-source-relationship-guards.js.map +1 -0
- package/dist/commonjs/event-sources/sqs-event-source.d.ts +7 -4
- package/dist/commonjs/event-sources/sqs-event-source.d.ts.map +1 -1
- package/dist/commonjs/event-sources/sqs-event-source.js +7 -4
- package/dist/commonjs/event-sources/sqs-event-source.js.map +1 -1
- package/dist/commonjs/function-alarms.d.ts.map +1 -1
- package/dist/commonjs/function-alarms.js +111 -47
- package/dist/commonjs/function-alarms.js.map +1 -1
- package/dist/commonjs/function-builder.d.ts.map +1 -1
- package/dist/commonjs/function-builder.js +7 -0
- package/dist/commonjs/function-builder.js.map +1 -1
- package/dist/commonjs/index.d.ts +2 -0
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +6 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/esm/alarm-config.d.ts +22 -0
- package/dist/esm/alarm-config.d.ts.map +1 -1
- package/dist/esm/alarm-defaults.d.ts +1 -0
- package/dist/esm/alarm-defaults.d.ts.map +1 -1
- package/dist/esm/alarm-defaults.js +15 -0
- package/dist/esm/alarm-defaults.js.map +1 -1
- package/dist/esm/event-sources/composure-event-source.d.ts +4 -4
- package/dist/esm/event-sources/composure-event-source.d.ts.map +1 -1
- package/dist/esm/event-sources/composure-event-source.js +7 -3
- package/dist/esm/event-sources/composure-event-source.js.map +1 -1
- package/dist/esm/event-sources/dynamodb-event-source.d.ts +55 -0
- package/dist/esm/event-sources/dynamodb-event-source.d.ts.map +1 -0
- package/dist/esm/event-sources/dynamodb-event-source.js +84 -0
- package/dist/esm/event-sources/dynamodb-event-source.js.map +1 -0
- package/dist/esm/event-sources/event-source-relationship-guards.d.ts +28 -0
- package/dist/esm/event-sources/event-source-relationship-guards.d.ts.map +1 -0
- package/dist/esm/event-sources/event-source-relationship-guards.js +102 -0
- package/dist/esm/event-sources/event-source-relationship-guards.js.map +1 -0
- package/dist/esm/event-sources/sqs-event-source.d.ts +7 -4
- package/dist/esm/event-sources/sqs-event-source.d.ts.map +1 -1
- package/dist/esm/event-sources/sqs-event-source.js +7 -4
- package/dist/esm/event-sources/sqs-event-source.js.map +1 -1
- package/dist/esm/function-alarms.d.ts.map +1 -1
- package/dist/esm/function-alarms.js +112 -48
- package/dist/esm/function-alarms.js.map +1 -1
- package/dist/esm/function-builder.d.ts.map +1 -1
- package/dist/esm/function-builder.js +7 -0
- package/dist/esm/function-builder.js.map +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/package.json +15 -5
package/README.md
CHANGED
|
@@ -125,16 +125,21 @@ Opt back into CDK's auto-created role attached to `AWSLambdaBasicExecutionRole`.
|
|
|
125
125
|
|
|
126
126
|
The builder creates [AWS-recommended CloudWatch alarms](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Best_Practice_Recommended_Alarms_AWS_Services.html#Lambda) by default. No alarm actions are configured — access alarms from the build result to add SNS topics or other actions.
|
|
127
127
|
|
|
128
|
-
| Alarm | Metric | Default threshold | Created when
|
|
129
|
-
| ------------------------ | --------------------------------- | --------------------------- |
|
|
130
|
-
| `errors` | Errors (Sum, 1 min) | > 0 | Always
|
|
131
|
-
| `throttles` | Throttles (Sum, 1 min) | > 0 | Always
|
|
132
|
-
| `duration` | Duration (p99, 1 min) | > 90% of configured timeout | `timeout` is set
|
|
133
|
-
| `concurrentExecutions` | ConcurrentExecutions (Max, 1 min) | >= 80% of reserved limit | `reservedConcurrentExecutions` is set
|
|
134
|
-
| `<key>FailedInvocations` | FailedInvokeEventCount (Sum) | > 0 | An SQS
|
|
135
|
-
| `<key>DroppedEvents` | DroppedEventCount (Sum) | > 0 | An SQS
|
|
128
|
+
| Alarm | Metric | Default threshold | Created when |
|
|
129
|
+
| ------------------------ | --------------------------------- | --------------------------- | -------------------------------------- |
|
|
130
|
+
| `errors` | Errors (Sum, 1 min) | > 0 | Always |
|
|
131
|
+
| `throttles` | Throttles (Sum, 1 min) | > 0 | Always |
|
|
132
|
+
| `duration` | Duration (p99, 1 min) | > 90% of configured timeout | `timeout` is set |
|
|
133
|
+
| `concurrentExecutions` | ConcurrentExecutions (Max, 1 min) | >= 80% of reserved limit | `reservedConcurrentExecutions` is set |
|
|
134
|
+
| `<key>FailedInvocations` | FailedInvokeEventCount (Sum) | > 0 | An SQS or DynamoDB source is attached |
|
|
135
|
+
| `<key>DroppedEvents` | DroppedEventCount (Sum) | > 0 | An SQS or DynamoDB source is attached |
|
|
136
|
+
| `iteratorAge` | IteratorAge (Max, 1 min) | > 60000 ms for 3 min¹ | A stream source (DynamoDB) is attached |
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
¹ AWS recommends alarming on `IteratorAge` for stream consumers but prescribes no fixed threshold — it is workload dependent. The 60s/3-minute default is deliberately conservative; tune it per workload via `eventSourceIteratorAge`.
|
|
139
|
+
|
|
140
|
+
The per-mapping event-source alarms are contextual: one pair is created per event source attached via `addEventSource` (see [Event sources](#event-sources)) whose kind emits per-mapping ESM metrics. Each alarm's key is the event source's key suffixed with `FailedInvocations` / `DroppedEvents` — e.g. an event source added as `"orders"` produces `ordersFailedInvocations` and `ordersDroppedEvents`. The `eventSourceFailedInvocations` / `eventSourceDroppedEvents` fields on `recommendedAlarms` tune every such alarm.
|
|
141
|
+
|
|
142
|
+
`iteratorAge` is different: `IteratorAge` is a function-level metric, so a single alarm (keyed `iteratorAge`) is created whenever at least one stream source (currently DynamoDB streams) is attached, regardless of how many. It warns when the consumer falls behind its stream. Tune or disable it via the `eventSourceIteratorAge` field on `recommendedAlarms`.
|
|
138
143
|
|
|
139
144
|
The defaults are exported as `FUNCTION_ALARM_DEFAULTS` for visibility and testing:
|
|
140
145
|
|
|
@@ -226,9 +231,10 @@ for (const alarm of Object.values(result.alarms)) {
|
|
|
226
231
|
function can have many event sources of mixed types, so the hook is repeatable
|
|
227
232
|
and keyed — the resolved sources are exposed on `result.eventSources`.
|
|
228
233
|
|
|
229
|
-
Pass a `ComposureEventSource` from a factory (`sqsEventSource
|
|
230
|
-
its own `Resolvable` so the source queue
|
|
231
|
-
component, or a bare CDK `IEventSource` as
|
|
234
|
+
Pass a `ComposureEventSource` from a factory (`sqsEventSource`,
|
|
235
|
+
`dynamoEventSource`), which carries its own `Resolvable` so the source queue or
|
|
236
|
+
table can be a `ref()` to a sibling component, or a bare CDK `IEventSource` as
|
|
237
|
+
an escape hatch.
|
|
232
238
|
|
|
233
239
|
```ts
|
|
234
240
|
import { compose, ref } from "@composurecdk/core";
|
|
@@ -250,7 +256,44 @@ const system = compose(
|
|
|
250
256
|
|
|
251
257
|
The source is attached _after_ the function and its least-privilege execution
|
|
252
258
|
role exist, so the `source.bind(fn)` that `addEventSource` performs grants the
|
|
253
|
-
|
|
259
|
+
consume permission (SQS `ReceiveMessage`, or DynamoDB `grantStreamRead`) onto
|
|
260
|
+
the builder's role rather than CDK's auto-role.
|
|
261
|
+
|
|
262
|
+
`dynamoEventSource(table, props?)` mirrors the SQS factory for DynamoDB streams.
|
|
263
|
+
The table must have a stream enabled (via the [DynamoDB builder](../dynamodb)'s
|
|
264
|
+
`.dynamoStream(...)` / `.stream(...)`, or `TableProps.stream`); otherwise CDK
|
|
265
|
+
throws `DynamoDB Streams must be enabled` at build time. `startingPosition`
|
|
266
|
+
defaults to `LATEST` and is overridable via `props`:
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { StartingPosition } from "aws-cdk-lib/aws-lambda";
|
|
270
|
+
import { StreamViewType } from "aws-cdk-lib/aws-dynamodb";
|
|
271
|
+
import { compose, ref } from "@composurecdk/core";
|
|
272
|
+
import { createFunctionBuilder, dynamoEventSource } from "@composurecdk/lambda";
|
|
273
|
+
import { createTableV2Builder } from "@composurecdk/dynamodb";
|
|
274
|
+
|
|
275
|
+
compose(
|
|
276
|
+
{
|
|
277
|
+
orders: createTableV2Builder()
|
|
278
|
+
.partitionKey({ name: "pk", type: AttributeType.STRING })
|
|
279
|
+
.dynamoStream(StreamViewType.NEW_AND_OLD_IMAGES),
|
|
280
|
+
processor: createFunctionBuilder()
|
|
281
|
+
.runtime(Runtime.NODEJS_22_X)
|
|
282
|
+
.handler("index.handler")
|
|
283
|
+
.code(Code.fromAsset("lambda"))
|
|
284
|
+
.addEventSource(
|
|
285
|
+
"orders",
|
|
286
|
+
dynamoEventSource(
|
|
287
|
+
ref("orders", (r) => r.table),
|
|
288
|
+
{
|
|
289
|
+
startingPosition: StartingPosition.TRIM_HORIZON,
|
|
290
|
+
},
|
|
291
|
+
),
|
|
292
|
+
),
|
|
293
|
+
},
|
|
294
|
+
{ orders: [], processor: ["orders"] },
|
|
295
|
+
);
|
|
296
|
+
```
|
|
254
297
|
|
|
255
298
|
### Secure defaults
|
|
256
299
|
|
|
@@ -262,6 +305,15 @@ second `props` argument and exported as `DEFAULT_SQS_EVENT_SOURCE_PROPS`:
|
|
|
262
305
|
| `reportBatchItemFailures` | `true` | A single poison message fails only its own record, not the whole batch. CDK defaults this `false`. |
|
|
263
306
|
| `metricsConfig` | `{ metrics: [EventCount] }` | Enables the per-mapping ESM metrics that back the event-source contextual alarms. |
|
|
264
307
|
|
|
308
|
+
`dynamoEventSource` applies the same defaults plus `startingPosition`, exported
|
|
309
|
+
as `DEFAULT_DYNAMO_EVENT_SOURCE_PROPS`:
|
|
310
|
+
|
|
311
|
+
| Property | Default | Rationale |
|
|
312
|
+
| ------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
313
|
+
| `startingPosition` | `LATEST` | A newly-attached consumer reads from the stream tip, not the table's existing change history. |
|
|
314
|
+
| `reportBatchItemFailures` | `true` | A single poison record fails only its own record, not the whole batch. CDK defaults this `false`. |
|
|
315
|
+
| `metricsConfig` | `{ metrics: [EventCount] }` | Enables the per-mapping ESM metrics that back the event-source contextual alarms. |
|
|
316
|
+
|
|
265
317
|
### Cross-component invariants
|
|
266
318
|
|
|
267
319
|
AWS Well-Architected guidance spans the queue and the function — the source
|
|
@@ -271,9 +323,8 @@ today (the queue often arrives as an unresolved `ref()`); they are tracked in
|
|
|
271
323
|
[#123](https://github.com/laazyj/composureCDK/issues/123) and
|
|
272
324
|
[#124](https://github.com/laazyj/composureCDK/issues/124).
|
|
273
325
|
|
|
274
|
-
`kinesisEventSource`
|
|
275
|
-
|
|
276
|
-
and [#121](https://github.com/laazyj/composureCDK/issues/121).
|
|
326
|
+
`kinesisEventSource` is still deferred — see
|
|
327
|
+
[#120](https://github.com/laazyj/composureCDK/issues/120).
|
|
277
328
|
|
|
278
329
|
## Examples
|
|
279
330
|
|
|
@@ -110,5 +110,27 @@ export interface FunctionAlarmConfig {
|
|
|
110
110
|
* @see https://aws.amazon.com/blogs/compute/introducing-new-event-source-mapping-esm-metrics-for-aws-lambda/
|
|
111
111
|
*/
|
|
112
112
|
eventSourceDroppedEvents?: AlarmConfig | false;
|
|
113
|
+
/**
|
|
114
|
+
* Alarm when the function is falling behind a stream event source.
|
|
115
|
+
*
|
|
116
|
+
* Contextual: a single alarm is created when at least one stream event
|
|
117
|
+
* source (currently DynamoDB streams) is attached via
|
|
118
|
+
* {@link IFunctionBuilder.addEventSource}. Unlike the per-mapping
|
|
119
|
+
* {@link FunctionAlarmConfig.eventSourceFailedInvocations} /
|
|
120
|
+
* {@link FunctionAlarmConfig.eventSourceDroppedEvents} alarms, `IteratorAge`
|
|
121
|
+
* is a function-level metric, so there is one alarm per function (keyed
|
|
122
|
+
* `iteratorAge`) regardless of how many stream sources are attached.
|
|
123
|
+
*
|
|
124
|
+
* The threshold is an absolute age in milliseconds (not a percentage).
|
|
125
|
+
*
|
|
126
|
+
* Metric: `AWS/Lambda IteratorAge`, statistic Maximum, period 1 minute,
|
|
127
|
+
* dimensioned on `FunctionName`. AWS recommends alarming on this metric for
|
|
128
|
+
* stream consumers but does not prescribe a threshold (it is workload
|
|
129
|
+
* dependent); the default is a deliberately conservative > 60000 ms (60s) for
|
|
130
|
+
* 3 consecutive minutes.
|
|
131
|
+
*
|
|
132
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html
|
|
133
|
+
*/
|
|
134
|
+
eventSourceIteratorAge?: AlarmConfig | false;
|
|
113
135
|
}
|
|
114
136
|
//# sourceMappingURL=alarm-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alarm-config.d.ts","sourceRoot":"","sources":["../../src/alarm-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG;IACnE;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC,CAAC;AAE/F;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAE7B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAErD;;;;;;;;;;;;;OAaG;IACH,4BAA4B,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEnD;;;;;;;;;;;;;OAaG;IACH,wBAAwB,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"alarm-config.d.ts","sourceRoot":"","sources":["../../src/alarm-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG;IACnE;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAC,CAAC;AAE/F;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAE7B;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEhC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IAErD;;;;;;;;;;;;;OAaG;IACH,4BAA4B,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAEnD;;;;;;;;;;;;;OAaG;IACH,wBAAwB,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;IAE/C;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,sBAAsB,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC;CAC9C"}
|
|
@@ -8,6 +8,7 @@ interface FunctionAlarmDefaults {
|
|
|
8
8
|
concurrentExecutions: PercentageAlarmConfigDefaults;
|
|
9
9
|
eventSourceFailedInvocations: AlarmConfigDefaults;
|
|
10
10
|
eventSourceDroppedEvents: AlarmConfigDefaults;
|
|
11
|
+
eventSourceIteratorAge: AlarmConfigDefaults;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* AWS-recommended default alarm configuration for Lambda functions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alarm-defaults.d.ts","sourceRoot":"","sources":["../../src/alarm-defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAEvE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,6BAA6B,CAAC;IACxC,oBAAoB,EAAE,6BAA6B,CAAC;IACpD,4BAA4B,EAAE,mBAAmB,CAAC;IAClD,wBAAwB,EAAE,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"alarm-defaults.d.ts","sourceRoot":"","sources":["../../src/alarm-defaults.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAC;AAEvE,UAAU,qBAAqB;IAC7B,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,mBAAmB,CAAC;IAC5B,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,EAAE,6BAA6B,CAAC;IACxC,oBAAoB,EAAE,6BAA6B,CAAC;IACpD,4BAA4B,EAAE,mBAAmB,CAAC;IAClD,wBAAwB,EAAE,mBAAmB,CAAC;IAC9C,sBAAsB,EAAE,mBAAmB,CAAC;CAC7C;AAED;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,qBAwErC,CAAC"}
|
|
@@ -57,5 +57,20 @@ exports.FUNCTION_ALARM_DEFAULTS = {
|
|
|
57
57
|
datapointsToAlarm: 1,
|
|
58
58
|
treatMissingData: aws_cloudwatch_1.TreatMissingData.NOT_BREACHING,
|
|
59
59
|
},
|
|
60
|
+
/**
|
|
61
|
+
* The consumer falling behind the stream risks data loss once records age
|
|
62
|
+
* past the stream's 24h retention. AWS recommends alarming on `IteratorAge`
|
|
63
|
+
* for stream consumers but publishes no fixed threshold — the right value is
|
|
64
|
+
* workload dependent. 60s of sustained lag for 3 consecutive minutes is a
|
|
65
|
+
* deliberately conservative default; tune via `eventSourceIteratorAge`. Idle
|
|
66
|
+
* functions emit no datapoints and stay OK (`NOT_BREACHING`).
|
|
67
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html
|
|
68
|
+
*/
|
|
69
|
+
eventSourceIteratorAge: {
|
|
70
|
+
threshold: 60_000,
|
|
71
|
+
evaluationPeriods: 3,
|
|
72
|
+
datapointsToAlarm: 3,
|
|
73
|
+
treatMissingData: aws_cloudwatch_1.TreatMissingData.NOT_BREACHING,
|
|
74
|
+
},
|
|
60
75
|
};
|
|
61
76
|
//# sourceMappingURL=alarm-defaults.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"alarm-defaults.js","sourceRoot":"","sources":["../../src/alarm-defaults.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;
|
|
1
|
+
{"version":3,"file":"alarm-defaults.js","sourceRoot":"","sources":["../../src/alarm-defaults.ts"],"names":[],"mappings":";;;AAAA,+DAA8D;AAe9D;;;;GAIG;AACU,QAAA,uBAAuB,GAA0B;IAC5D,OAAO,EAAE,IAAI;IAEb,qDAAqD;IACrD,MAAM,EAAE;QACN,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED,6DAA6D;IAC7D,SAAS,EAAE;QACT,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED;;;OAGG;IACH,QAAQ,EAAE;QACR,gBAAgB,EAAE,GAAG;QACrB,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED;;;OAGG;IACH,oBAAoB,EAAE;QACpB,gBAAgB,EAAE,GAAG;QACrB,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED,sFAAsF;IACtF,4BAA4B,EAAE;QAC5B,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED,mDAAmD;IACnD,wBAAwB,EAAE;QACxB,SAAS,EAAE,CAAC;QACZ,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;IAED;;;;;;;;OAQG;IACH,sBAAsB,EAAE;QACtB,SAAS,EAAE,MAAM;QACjB,iBAAiB,EAAE,CAAC;QACpB,iBAAiB,EAAE,CAAC;QACpB,gBAAgB,EAAE,iCAAgB,CAAC,aAAa;KACjD;CACF,CAAC"}
|
|
@@ -9,7 +9,7 @@ import type { Resolvable } from "@composurecdk/core";
|
|
|
9
9
|
* straight to {@link IFunctionBuilder.addEventSource} as an escape hatch —
|
|
10
10
|
* the builder still attaches it, but cannot reason about it.
|
|
11
11
|
*/
|
|
12
|
-
export type EventSourceKind = "sqs" | "unknown";
|
|
12
|
+
export type EventSourceKind = "sqs" | "dynamodb" | "unknown";
|
|
13
13
|
/** @internal — brands {@link ComposureEventSource} so the guard is unambiguous. */
|
|
14
14
|
declare const COMPOSURE_EVENT_SOURCE: unique symbol;
|
|
15
15
|
/**
|
|
@@ -40,9 +40,9 @@ export declare function composureEventSource(kind: EventSourceKind, source: Reso
|
|
|
40
40
|
/**
|
|
41
41
|
* Reads the event source mapping UUID off a bound CDK source, keyed by
|
|
42
42
|
* {@link EventSourceKind}. Defined only for kinds whose per-mapping ESM
|
|
43
|
-
* metrics back contextual alarms (
|
|
44
|
-
* the reader after `addEventSource` so the binding exists. Keying off
|
|
45
|
-
* — like {@link EVENT_SOURCE_ALARM_SPECS} — keeps the builder from
|
|
43
|
+
* metrics back contextual alarms (SQS and DynamoDB streams); `FunctionBuilder`
|
|
44
|
+
* invokes the reader after `addEventSource` so the binding exists. Keying off
|
|
45
|
+
* `kind` — like {@link EVENT_SOURCE_ALARM_SPECS} — keeps the builder from
|
|
46
46
|
* `instanceof`-ing CDK source classes.
|
|
47
47
|
*
|
|
48
48
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composure-event-source.d.ts","sourceRoot":"","sources":["../../../src/event-sources/composure-event-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"composure-event-source.d.ts","sourceRoot":"","sources":["../../../src/event-sources/composure-event-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,UAAU,GAAG,SAAS,CAAC;AAE7D,mFAAmF;AACnF,QAAA,MAAM,sBAAsB,eAAgD,CAAC;AAE7E;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,gBAAgB;IAChB,QAAQ,CAAC,CAAC,sBAAsB,CAAC,EAAE,IAAI,CAAC;IAExC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAE/B;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;CAC3C;AAED,oEAAoE;AACpE,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,eAAe,EACrB,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,GAC/B,oBAAoB,CAEtB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAClD,eAAe,EACf,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,MAAM,CAAC,GAAG,SAAS,CAW9C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,oBAAoB,GAAG,YAAY,GACzC,KAAK,IAAI,oBAAoB,CAE/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,GAAG,EAAE,MAAM,CAAC;IAEZ,8DAA8D;IAC9D,IAAI,EAAE,eAAe,CAAC;IAEtB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B"}
|
|
@@ -12,9 +12,9 @@ function composureEventSource(kind, source) {
|
|
|
12
12
|
/**
|
|
13
13
|
* Reads the event source mapping UUID off a bound CDK source, keyed by
|
|
14
14
|
* {@link EventSourceKind}. Defined only for kinds whose per-mapping ESM
|
|
15
|
-
* metrics back contextual alarms (
|
|
16
|
-
* the reader after `addEventSource` so the binding exists. Keying off
|
|
17
|
-
* — like {@link EVENT_SOURCE_ALARM_SPECS} — keeps the builder from
|
|
15
|
+
* metrics back contextual alarms (SQS and DynamoDB streams); `FunctionBuilder`
|
|
16
|
+
* invokes the reader after `addEventSource` so the binding exists. Keying off
|
|
17
|
+
* `kind` — like {@link EVENT_SOURCE_ALARM_SPECS} — keeps the builder from
|
|
18
18
|
* `instanceof`-ing CDK source classes.
|
|
19
19
|
*
|
|
20
20
|
* @internal
|
|
@@ -24,6 +24,10 @@ exports.EVENT_SOURCE_MAPPING_ID_READERS = {
|
|
|
24
24
|
// constructs the `SqsEventSource` in the same call — kind and concrete class
|
|
25
25
|
// move in lockstep.
|
|
26
26
|
sqs: (bound) => bound.eventSourceMappingId,
|
|
27
|
+
// Safe: the `"dynamodb"` kind is only ever assigned by `dynamoEventSource()`,
|
|
28
|
+
// which constructs the `DynamoEventSource` in the same call — kind and
|
|
29
|
+
// concrete class move in lockstep.
|
|
30
|
+
dynamodb: (bound) => bound.eventSourceMappingId,
|
|
27
31
|
unknown: undefined,
|
|
28
32
|
};
|
|
29
33
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composure-event-source.js","sourceRoot":"","sources":["../../../src/event-sources/composure-event-source.ts"],"names":[],"mappings":";;;AA6CA,oDAKC;
|
|
1
|
+
{"version":3,"file":"composure-event-source.js","sourceRoot":"","sources":["../../../src/event-sources/composure-event-source.ts"],"names":[],"mappings":";;;AA6CA,oDAKC;AA+BD,wDAIC;AAtED,mFAAmF;AACnF,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AA4B7E,oEAAoE;AACpE,SAAgB,oBAAoB,CAClC,IAAqB,EACrB,MAAgC;IAEhC,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;;;;;GASG;AACU,QAAA,+BAA+B,GAGxC;IACF,4EAA4E;IAC5E,6EAA6E;IAC7E,oBAAoB;IACpB,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAE,KAAwB,CAAC,oBAAoB;IAC9D,8EAA8E;IAC9E,uEAAuE;IACvE,mCAAmC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAE,KAA2B,CAAC,oBAAoB;IACtE,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF;;;GAGG;AACH,SAAgB,sBAAsB,CACpC,KAA0C;IAE1C,OAAO,sBAAsB,IAAI,KAAK,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ITable } from "aws-cdk-lib/aws-dynamodb";
|
|
2
|
+
import { type DynamoEventSourceProps } from "aws-cdk-lib/aws-lambda-event-sources";
|
|
3
|
+
import { type Resolvable } from "@composurecdk/core";
|
|
4
|
+
import { type ComposureEventSource } from "./composure-event-source.js";
|
|
5
|
+
/**
|
|
6
|
+
* Secure, AWS-recommended defaults applied to every DynamoDB stream event
|
|
7
|
+
* source built with {@link dynamoEventSource}. Each property can be overridden
|
|
8
|
+
* via the factory's `props` argument.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_DYNAMO_EVENT_SOURCE_PROPS: Pick<DynamoEventSourceProps, "startingPosition" | "reportBatchItemFailures" | "metricsConfig">;
|
|
11
|
+
/**
|
|
12
|
+
* Wraps a DynamoDB table's change stream as a Lambda {@link IEventSource},
|
|
13
|
+
* deferring resolution when the table is a `ref()` to a sibling component's
|
|
14
|
+
* output.
|
|
15
|
+
*
|
|
16
|
+
* Follows the `events/targets` factory shape: register the result with
|
|
17
|
+
* {@link IFunctionBuilder.addEventSource} and the builder resolves the
|
|
18
|
+
* `ref()`, attaches the source, and (because `addEventSource` calls
|
|
19
|
+
* `source.bind(fn)`) grants the function's least-privilege execution role
|
|
20
|
+
* permission to read the stream via `grantStreamRead`.
|
|
21
|
+
*
|
|
22
|
+
* Applies {@link DEFAULT_DYNAMO_EVENT_SOURCE_PROPS}; pass `props` to override.
|
|
23
|
+
*
|
|
24
|
+
* ## Cross-component invariant (enforced by CDK at bind time)
|
|
25
|
+
*
|
|
26
|
+
* The table must have a stream enabled (via the table builder's
|
|
27
|
+
* `.dynamoStream(...)` / `.stream(...)`, or `TableProps.stream`). If it does
|
|
28
|
+
* not, CDK's `DynamoEventSource.bind()` throws `DynamoDB Streams must be
|
|
29
|
+
* enabled on the table` when the function is built — the table often arrives
|
|
30
|
+
* as a `ref()` that is not resolvable at configuration time, so this is not
|
|
31
|
+
* validated earlier.
|
|
32
|
+
*
|
|
33
|
+
* @param table - The source table, concrete or a `ref()` to a sibling.
|
|
34
|
+
* @param props - Overrides for {@link DEFAULT_DYNAMO_EVENT_SOURCE_PROPS} and
|
|
35
|
+
* any other {@link DynamoEventSourceProps}.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* compose(
|
|
40
|
+
* {
|
|
41
|
+
* orders: createTableV2Builder()
|
|
42
|
+
* .partitionKey({ name: "pk", type: AttributeType.STRING })
|
|
43
|
+
* .dynamoStream(StreamViewType.NEW_AND_OLD_IMAGES),
|
|
44
|
+
* processor: createFunctionBuilder()
|
|
45
|
+
* .runtime(Runtime.NODEJS_22_X)
|
|
46
|
+
* .handler("index.handler")
|
|
47
|
+
* .code(Code.fromAsset("lambda"))
|
|
48
|
+
* .addEventSource("orders", dynamoEventSource(ref("orders", (r) => r.table))),
|
|
49
|
+
* },
|
|
50
|
+
* { orders: [], processor: ["orders"] },
|
|
51
|
+
* );
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function dynamoEventSource(table: Resolvable<ITable>, props?: DynamoEventSourceProps): ComposureEventSource;
|
|
55
|
+
//# sourceMappingURL=dynamodb-event-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamodb-event-source.d.ts","sourceRoot":"","sources":["../../../src/event-sources/dynamodb-event-source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,KAAK,oBAAoB,EAAwB,MAAM,6BAA6B,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,EAAE,IAAI,CAClD,sBAAsB,EACtB,kBAAkB,GAAG,yBAAyB,GAAG,eAAe,CA0BjE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,EACzB,KAAK,CAAC,EAAE,sBAAsB,GAC7B,oBAAoB,CAMtB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_DYNAMO_EVENT_SOURCE_PROPS = void 0;
|
|
4
|
+
exports.dynamoEventSource = dynamoEventSource;
|
|
5
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
|
6
|
+
const aws_lambda_event_sources_1 = require("aws-cdk-lib/aws-lambda-event-sources");
|
|
7
|
+
const core_1 = require("@composurecdk/core");
|
|
8
|
+
const composure_event_source_js_1 = require("./composure-event-source.js");
|
|
9
|
+
/**
|
|
10
|
+
* Secure, AWS-recommended defaults applied to every DynamoDB stream event
|
|
11
|
+
* source built with {@link dynamoEventSource}. Each property can be overridden
|
|
12
|
+
* via the factory's `props` argument.
|
|
13
|
+
*/
|
|
14
|
+
exports.DEFAULT_DYNAMO_EVENT_SOURCE_PROPS = {
|
|
15
|
+
/**
|
|
16
|
+
* Start reading from the tip of the stream so a newly-attached consumer does
|
|
17
|
+
* not replay the table's existing change history on first deploy. Override
|
|
18
|
+
* with {@link StartingPosition.TRIM_HORIZON} to reprocess from the oldest
|
|
19
|
+
* record in the stream.
|
|
20
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html
|
|
21
|
+
*/
|
|
22
|
+
startingPosition: aws_lambda_1.StartingPosition.LATEST,
|
|
23
|
+
/**
|
|
24
|
+
* Report partial batch failures so a single poison record does not fail the
|
|
25
|
+
* whole batch and force redelivery of already-processed records. CDK
|
|
26
|
+
* defaults this to `false`.
|
|
27
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/with-ddb.html#services-ddb-batchfailurereporting
|
|
28
|
+
*/
|
|
29
|
+
reportBatchItemFailures: true,
|
|
30
|
+
/**
|
|
31
|
+
* Enable the per-mapping `EventCount` ESM metrics (`FailedInvokeEventCount`,
|
|
32
|
+
* `DroppedEventCount`, …). They emit only when opted in, and the
|
|
33
|
+
* event-source contextual alarms on {@link IFunctionBuilder} depend on them.
|
|
34
|
+
* @see https://aws.amazon.com/blogs/compute/introducing-new-event-source-mapping-esm-metrics-for-aws-lambda/
|
|
35
|
+
*/
|
|
36
|
+
metricsConfig: { metrics: [aws_lambda_1.MetricType.EVENT_COUNT] },
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Wraps a DynamoDB table's change stream as a Lambda {@link IEventSource},
|
|
40
|
+
* deferring resolution when the table is a `ref()` to a sibling component's
|
|
41
|
+
* output.
|
|
42
|
+
*
|
|
43
|
+
* Follows the `events/targets` factory shape: register the result with
|
|
44
|
+
* {@link IFunctionBuilder.addEventSource} and the builder resolves the
|
|
45
|
+
* `ref()`, attaches the source, and (because `addEventSource` calls
|
|
46
|
+
* `source.bind(fn)`) grants the function's least-privilege execution role
|
|
47
|
+
* permission to read the stream via `grantStreamRead`.
|
|
48
|
+
*
|
|
49
|
+
* Applies {@link DEFAULT_DYNAMO_EVENT_SOURCE_PROPS}; pass `props` to override.
|
|
50
|
+
*
|
|
51
|
+
* ## Cross-component invariant (enforced by CDK at bind time)
|
|
52
|
+
*
|
|
53
|
+
* The table must have a stream enabled (via the table builder's
|
|
54
|
+
* `.dynamoStream(...)` / `.stream(...)`, or `TableProps.stream`). If it does
|
|
55
|
+
* not, CDK's `DynamoEventSource.bind()` throws `DynamoDB Streams must be
|
|
56
|
+
* enabled on the table` when the function is built — the table often arrives
|
|
57
|
+
* as a `ref()` that is not resolvable at configuration time, so this is not
|
|
58
|
+
* validated earlier.
|
|
59
|
+
*
|
|
60
|
+
* @param table - The source table, concrete or a `ref()` to a sibling.
|
|
61
|
+
* @param props - Overrides for {@link DEFAULT_DYNAMO_EVENT_SOURCE_PROPS} and
|
|
62
|
+
* any other {@link DynamoEventSourceProps}.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* compose(
|
|
67
|
+
* {
|
|
68
|
+
* orders: createTableV2Builder()
|
|
69
|
+
* .partitionKey({ name: "pk", type: AttributeType.STRING })
|
|
70
|
+
* .dynamoStream(StreamViewType.NEW_AND_OLD_IMAGES),
|
|
71
|
+
* processor: createFunctionBuilder()
|
|
72
|
+
* .runtime(Runtime.NODEJS_22_X)
|
|
73
|
+
* .handler("index.handler")
|
|
74
|
+
* .code(Code.fromAsset("lambda"))
|
|
75
|
+
* .addEventSource("orders", dynamoEventSource(ref("orders", (r) => r.table))),
|
|
76
|
+
* },
|
|
77
|
+
* { orders: [], processor: ["orders"] },
|
|
78
|
+
* );
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
function dynamoEventSource(table, props) {
|
|
82
|
+
const merged = { ...exports.DEFAULT_DYNAMO_EVENT_SOURCE_PROPS, ...props };
|
|
83
|
+
const source = (0, core_1.isRef)(table)
|
|
84
|
+
? table.map((resolved) => new aws_lambda_event_sources_1.DynamoEventSource(resolved, merged))
|
|
85
|
+
: new aws_lambda_event_sources_1.DynamoEventSource(table, merged);
|
|
86
|
+
return (0, composure_event_source_js_1.composureEventSource)("dynamodb", source);
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=dynamodb-event-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamodb-event-source.js","sourceRoot":"","sources":["../../../src/event-sources/dynamodb-event-source.ts"],"names":[],"mappings":";;;AAwFA,8CASC;AA/FD,uDAAsE;AACtE,mFAG8C;AAC9C,6CAA4D;AAC5D,2EAA8F;AAE9F;;;;GAIG;AACU,QAAA,iCAAiC,GAG1C;IACF;;;;;;OAMG;IACH,gBAAgB,EAAE,6BAAgB,CAAC,MAAM;IAEzC;;;;;OAKG;IACH,uBAAuB,EAAE,IAAI;IAE7B;;;;;OAKG;IACH,aAAa,EAAE,EAAE,OAAO,EAAE,CAAC,uBAAU,CAAC,WAAW,CAAC,EAAE;CACrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,SAAgB,iBAAiB,CAC/B,KAAyB,EACzB,KAA8B;IAE9B,MAAM,MAAM,GAA2B,EAAE,GAAG,yCAAiC,EAAE,GAAG,KAAK,EAAE,CAAC;IAC1F,MAAM,MAAM,GAA6B,IAAA,YAAK,EAAC,KAAK,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,4CAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAClE,CAAC,CAAC,IAAI,4CAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,IAAA,gDAAoB,EAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Duration } from "aws-cdk-lib";
|
|
2
|
+
import type { Function as LambdaFunction, IEventSource } from "aws-cdk-lib/aws-lambda";
|
|
3
|
+
import type { EventSourceKind } from "./composure-event-source.js";
|
|
4
|
+
/**
|
|
5
|
+
* Suppression id for the SQS visibility-timeout relationship guard. Stable and
|
|
6
|
+
* part of the public surface — silence the warning with
|
|
7
|
+
* `Annotations.of(scope).acknowledgeWarning(SQS_VISIBILITY_TIMEOUT_WARNING_ID)`,
|
|
8
|
+
* so it must not be renamed casually.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SQS_VISIBILITY_TIMEOUT_WARNING_ID = "@composurecdk/lambda:sqs-visibility-timeout";
|
|
11
|
+
/**
|
|
12
|
+
* Guards a cross-component relationship that spans an attached event source and
|
|
13
|
+
* its consumer function. `FunctionBuilder` dispatches on {@link EventSourceKind}
|
|
14
|
+
* so it never has to `instanceof` CDK internals — see ADR-0011.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export type EventSourceRelationshipGuard = (fn: LambdaFunction, id: string, key: string, bound: IEventSource, timeout: Duration | undefined) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Per-kind relationship guards, keyed by {@link EventSourceKind}. A kind maps to
|
|
21
|
+
* the (possibly empty) list of relationships to guard for a source of that kind
|
|
22
|
+
* — SQS gains a second entry for the `maxReceiveCount` floor (#124), and a bare
|
|
23
|
+
* escape-hatch source attached as `"unknown"` has none.
|
|
24
|
+
*
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare const EVENT_SOURCE_RELATIONSHIP_GUARDS: Record<EventSourceKind, EventSourceRelationshipGuard[]>;
|
|
28
|
+
//# sourceMappingURL=event-source-relationship-guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-source-relationship-guards.d.ts","sourceRoot":"","sources":["../../../src/event-sources/event-source-relationship-guards.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqC,KAAK,QAAQ,EAAS,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,QAAQ,IAAI,cAAc,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAIvF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAiBnE;;;;;GAKG;AACH,eAAO,MAAM,iCAAiC,gDAAgD,CAAC;AAE/F;;;;;;GAMG;AACH,MAAM,MAAM,4BAA4B,GAAG,CACzC,EAAE,EAAE,cAAc,EAClB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,QAAQ,GAAG,SAAS,KAC1B,IAAI,CAAC;AAEV;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,EAAE,MAAM,CACnD,eAAe,EACf,4BAA4B,EAAE,CAK/B,CAAC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EVENT_SOURCE_RELATIONSHIP_GUARDS = exports.SQS_VISIBILITY_TIMEOUT_WARNING_ID = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const aws_sqs_1 = require("aws-cdk-lib/aws-sqs");
|
|
6
|
+
/**
|
|
7
|
+
* AWS guidance: an SQS source queue's `visibilityTimeout` should be at least
|
|
8
|
+
* this multiple of the consumer function's `timeout`, so Lambda has room to
|
|
9
|
+
* retry a throttled batch before a message becomes visible again.
|
|
10
|
+
*
|
|
11
|
+
* @see https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
|
|
12
|
+
*/
|
|
13
|
+
const SQS_VISIBILITY_TIMEOUT_MULTIPLIER = 6;
|
|
14
|
+
/** Lambda's own default `timeout` when none is set (CDK leaves it unset). */
|
|
15
|
+
const LAMBDA_DEFAULT_TIMEOUT_SECONDS = 3;
|
|
16
|
+
/** SQS's own default `visibilityTimeout` when none is set (applied by CloudFormation). */
|
|
17
|
+
const SQS_DEFAULT_VISIBILITY_TIMEOUT_SECONDS = 30;
|
|
18
|
+
/**
|
|
19
|
+
* Suppression id for the SQS visibility-timeout relationship guard. Stable and
|
|
20
|
+
* part of the public surface — silence the warning with
|
|
21
|
+
* `Annotations.of(scope).acknowledgeWarning(SQS_VISIBILITY_TIMEOUT_WARNING_ID)`,
|
|
22
|
+
* so it must not be renamed casually.
|
|
23
|
+
*/
|
|
24
|
+
exports.SQS_VISIBILITY_TIMEOUT_WARNING_ID = "@composurecdk/lambda:sqs-visibility-timeout";
|
|
25
|
+
/**
|
|
26
|
+
* Per-kind relationship guards, keyed by {@link EventSourceKind}. A kind maps to
|
|
27
|
+
* the (possibly empty) list of relationships to guard for a source of that kind
|
|
28
|
+
* — SQS gains a second entry for the `maxReceiveCount` floor (#124), and a bare
|
|
29
|
+
* escape-hatch source attached as `"unknown"` has none.
|
|
30
|
+
*
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
exports.EVENT_SOURCE_RELATIONSHIP_GUARDS = {
|
|
34
|
+
sqs: [guardSqsVisibilityTimeout],
|
|
35
|
+
dynamodb: [],
|
|
36
|
+
unknown: [],
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The source queue behind a bound SQS event source. Safe cast: only reached for
|
|
40
|
+
* the `"sqs"` kind, whose source `sqsEventSource()` constructs as an
|
|
41
|
+
* {@link SqsEventSource} in the same call. `SqsEventSource.queue` is a public
|
|
42
|
+
* getter.
|
|
43
|
+
*/
|
|
44
|
+
function sqsQueue(bound) {
|
|
45
|
+
return bound.queue;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Warns when the source queue's `visibilityTimeout` is below 6× the consumer
|
|
49
|
+
* function's `timeout`. Registers a synth-time Aspect so it reads the queue's
|
|
50
|
+
* *final* value off its L1 `CfnQueue` — the value the L2 `Queue` does not
|
|
51
|
+
* re-expose — regardless of build order or later mutation (ADR-0011).
|
|
52
|
+
*/
|
|
53
|
+
function guardSqsVisibilityTimeout(fn, id, key, bound, timeout) {
|
|
54
|
+
const queue = sqsQueue(bound);
|
|
55
|
+
aws_cdk_lib_1.Aspects.of(fn).add({
|
|
56
|
+
visit(node) {
|
|
57
|
+
// The Aspect visits fn and its subtree; act once, against fn itself.
|
|
58
|
+
if (node !== fn)
|
|
59
|
+
return;
|
|
60
|
+
const target = targetVisibilityTimeoutSeconds(timeout);
|
|
61
|
+
if (target === undefined)
|
|
62
|
+
return; // token timeout — no concrete target to compare
|
|
63
|
+
const actual = readVisibilityTimeoutSeconds(queue);
|
|
64
|
+
if (actual === undefined || actual >= target)
|
|
65
|
+
return; // unknowable or compliant — stay quiet
|
|
66
|
+
aws_cdk_lib_1.Annotations.of(fn).addWarningV2(exports.SQS_VISIBILITY_TIMEOUT_WARNING_ID, `FunctionBuilder "${id}": SQS event source "${key}" — source queue visibilityTimeout is ` +
|
|
67
|
+
`${String(actual)}s but should be >= ${String(target)}s ` +
|
|
68
|
+
`(${String(SQS_VISIBILITY_TIMEOUT_MULTIPLIER)}x the function timeout) so Lambda can retry ` +
|
|
69
|
+
`a throttled batch. See https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html`);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The 6× target in seconds, derived from the function timeout (or Lambda's 3s
|
|
75
|
+
* default). `undefined` when the timeout is a token, which has no concrete
|
|
76
|
+
* target at synth time. Guards `isUnresolved` *before* converting, so a token
|
|
77
|
+
* Duration never reaches `toSeconds()`.
|
|
78
|
+
*/
|
|
79
|
+
function targetVisibilityTimeoutSeconds(timeout) {
|
|
80
|
+
if (timeout === undefined) {
|
|
81
|
+
return SQS_VISIBILITY_TIMEOUT_MULTIPLIER * LAMBDA_DEFAULT_TIMEOUT_SECONDS;
|
|
82
|
+
}
|
|
83
|
+
if (timeout.isUnresolved())
|
|
84
|
+
return undefined;
|
|
85
|
+
return SQS_VISIBILITY_TIMEOUT_MULTIPLIER * timeout.toSeconds();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The queue's resolved `visibilityTimeout` in seconds, read off its L1
|
|
89
|
+
* `CfnQueue` (the L2 `Queue` does not re-expose it). `undefined` when the queue
|
|
90
|
+
* is imported (no L1 child) or the value is an unresolved token; `30` (the SQS
|
|
91
|
+
* default) when the L1 carries no explicit value.
|
|
92
|
+
*/
|
|
93
|
+
function readVisibilityTimeoutSeconds(queue) {
|
|
94
|
+
const child = queue.node.defaultChild;
|
|
95
|
+
if (child === undefined ||
|
|
96
|
+
!aws_cdk_lib_1.CfnResource.isCfnResource(child) ||
|
|
97
|
+
child.cfnResourceType !== aws_sqs_1.CfnQueue.CFN_RESOURCE_TYPE_NAME) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const value = child.visibilityTimeout;
|
|
101
|
+
if (value === undefined)
|
|
102
|
+
return SQS_DEFAULT_VISIBILITY_TIMEOUT_SECONDS;
|
|
103
|
+
return aws_cdk_lib_1.Token.isUnresolved(value) ? undefined : value;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=event-source-relationship-guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-source-relationship-guards.js","sourceRoot":"","sources":["../../../src/event-sources/event-source-relationship-guards.ts"],"names":[],"mappings":";;;AAAA,6CAAsF;AAGtF,iDAA4D;AAI5D;;;;;;GAMG;AACH,MAAM,iCAAiC,GAAG,CAAC,CAAC;AAE5C,6EAA6E;AAC7E,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAEzC,0FAA0F;AAC1F,MAAM,sCAAsC,GAAG,EAAE,CAAC;AAElD;;;;;GAKG;AACU,QAAA,iCAAiC,GAAG,6CAA6C,CAAC;AAiB/F;;;;;;;GAOG;AACU,QAAA,gCAAgC,GAGzC;IACF,GAAG,EAAE,CAAC,yBAAyB,CAAC;IAChC,QAAQ,EAAE,EAAE;IACZ,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,KAAmB;IACnC,OAAQ,KAAwB,CAAC,KAAK,CAAC;AACzC,CAAC;AAED;;;;;GAKG;AACH,SAAS,yBAAyB,CAChC,EAAkB,EAClB,EAAU,EACV,GAAW,EACX,KAAmB,EACnB,OAA6B;IAE7B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9B,qBAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;QACjB,KAAK,CAAC,IAAgB;YACpB,qEAAqE;YACrE,IAAI,IAAI,KAAK,EAAE;gBAAE,OAAO;YAExB,MAAM,MAAM,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;YACvD,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,CAAC,gDAAgD;YAElF,MAAM,MAAM,GAAG,4BAA4B,CAAC,KAAK,CAAC,CAAC;YACnD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,IAAI,MAAM;gBAAE,OAAO,CAAC,uCAAuC;YAE7F,yBAAW,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,YAAY,CAC7B,yCAAiC,EACjC,oBAAoB,EAAE,wBAAwB,GAAG,wCAAwC;gBACvF,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,MAAM,CAAC,MAAM,CAAC,IAAI;gBACzD,IAAI,MAAM,CAAC,iCAAiC,CAAC,8CAA8C;gBAC3F,mFAAmF,CACtF,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,8BAA8B,CAAC,OAA6B;IACnE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,iCAAiC,GAAG,8BAA8B,CAAC;IAC5E,CAAC;IACD,IAAI,OAAO,CAAC,YAAY,EAAE;QAAE,OAAO,SAAS,CAAC;IAC7C,OAAO,iCAAiC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;AACjE,CAAC;AAED;;;;;GAKG;AACH,SAAS,4BAA4B,CAAC,KAAa;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;IACtC,IACE,KAAK,KAAK,SAAS;QACnB,CAAC,yBAAW,CAAC,aAAa,CAAC,KAAK,CAAC;QACjC,KAAK,CAAC,eAAe,KAAK,kBAAQ,CAAC,sBAAsB,EACzD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,KAAK,GAAI,KAAkB,CAAC,iBAAiB,CAAC;IACpD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,sCAAsC,CAAC;IACvE,OAAO,mBAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,CAAC"}
|
|
@@ -20,16 +20,19 @@ export declare const DEFAULT_SQS_EVENT_SOURCE_PROPS: Pick<SqsEventSourceProps, "
|
|
|
20
20
|
*
|
|
21
21
|
* Applies {@link DEFAULT_SQS_EVENT_SOURCE_PROPS}; pass `props` to override.
|
|
22
22
|
*
|
|
23
|
-
* ## Cross-component invariants
|
|
23
|
+
* ## Cross-component invariants
|
|
24
24
|
*
|
|
25
25
|
* AWS Well-Architected guidance spans the queue and the function:
|
|
26
26
|
* - the source queue's visibility timeout should be ≥ 6× the function
|
|
27
27
|
* timeout, leaving room for Lambda to retry a throttled batch;
|
|
28
28
|
* - the source queue's redrive `maxReceiveCount` should be ≥ 5 before the DLQ.
|
|
29
29
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* The visibility-timeout rule is enforced as a synth-time **relationship
|
|
31
|
+
* guard**: when this source is attached to a {@link IFunctionBuilder}, the
|
|
32
|
+
* builder reads the queue's resolved `visibilityTimeout` off its L1 `CfnQueue`
|
|
33
|
+
* (the `Queue` construct does not re-expose it) and warns, suppressibly, on an
|
|
34
|
+
* actual violation — see ADR-0011. The `maxReceiveCount` floor is tracked in
|
|
35
|
+
* laazyj/composureCDK#124.
|
|
33
36
|
*
|
|
34
37
|
* @param queue - The source queue, concrete or a `ref()` to a sibling.
|
|
35
38
|
* @param props - Overrides for {@link DEFAULT_SQS_EVENT_SOURCE_PROPS} and any
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqs-event-source.d.ts","sourceRoot":"","sources":["../../../src/event-sources/sqs-event-source.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,KAAK,oBAAoB,EAAwB,MAAM,6BAA6B,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,IAAI,CAC/C,mBAAmB,EACnB,yBAAyB,GAAG,eAAe,CAkB5C,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"sqs-event-source.d.ts","sourceRoot":"","sources":["../../../src/event-sources/sqs-event-source.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,KAAK,oBAAoB,EAAwB,MAAM,6BAA6B,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,IAAI,CAC/C,mBAAmB,EACnB,yBAAyB,GAAG,eAAe,CAkB5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,EACzB,KAAK,CAAC,EAAE,mBAAmB,GAC1B,oBAAoB,CAMtB"}
|
|
@@ -40,16 +40,19 @@ exports.DEFAULT_SQS_EVENT_SOURCE_PROPS = {
|
|
|
40
40
|
*
|
|
41
41
|
* Applies {@link DEFAULT_SQS_EVENT_SOURCE_PROPS}; pass `props` to override.
|
|
42
42
|
*
|
|
43
|
-
* ## Cross-component invariants
|
|
43
|
+
* ## Cross-component invariants
|
|
44
44
|
*
|
|
45
45
|
* AWS Well-Architected guidance spans the queue and the function:
|
|
46
46
|
* - the source queue's visibility timeout should be ≥ 6× the function
|
|
47
47
|
* timeout, leaving room for Lambda to retry a throttled batch;
|
|
48
48
|
* - the source queue's redrive `maxReceiveCount` should be ≥ 5 before the DLQ.
|
|
49
49
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
50
|
+
* The visibility-timeout rule is enforced as a synth-time **relationship
|
|
51
|
+
* guard**: when this source is attached to a {@link IFunctionBuilder}, the
|
|
52
|
+
* builder reads the queue's resolved `visibilityTimeout` off its L1 `CfnQueue`
|
|
53
|
+
* (the `Queue` construct does not re-expose it) and warns, suppressibly, on an
|
|
54
|
+
* actual violation — see ADR-0011. The `maxReceiveCount` floor is tracked in
|
|
55
|
+
* laazyj/composureCDK#124.
|
|
53
56
|
*
|
|
54
57
|
* @param queue - The source queue, concrete or a `ref()` to a sibling.
|
|
55
58
|
* @param props - Overrides for {@link DEFAULT_SQS_EVENT_SOURCE_PROPS} and any
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqs-event-source.js","sourceRoot":"","sources":["../../../src/event-sources/sqs-event-source.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sqs-event-source.js","sourceRoot":"","sources":["../../../src/event-sources/sqs-event-source.ts"],"names":[],"mappings":";;;AA+EA,wCASC;AAvFD,uDAAoD;AACpD,mFAAgG;AAEhG,6CAA4D;AAC5D,2EAA8F;AAE9F;;;;GAIG;AACU,QAAA,8BAA8B,GAGvC;IACF;;;;;;OAMG;IACH,uBAAuB,EAAE,IAAI;IAE7B;;;;;OAKG;IACH,aAAa,EAAE,EAAE,OAAO,EAAE,CAAC,uBAAU,CAAC,WAAW,CAAC,EAAE;CACrD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,SAAgB,cAAc,CAC5B,KAAyB,EACzB,KAA2B;IAE3B,MAAM,MAAM,GAAwB,EAAE,GAAG,sCAA8B,EAAE,GAAG,KAAK,EAAE,CAAC;IACpF,MAAM,MAAM,GAA6B,IAAA,YAAK,EAAC,KAAK,CAAC;QACnD,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,yCAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAC/D,CAAC,CAAC,IAAI,yCAAc,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACtC,OAAO,IAAA,gDAAoB,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
|