@composurecdk/lambda 0.10.0 → 0.10.2
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 +175 -0
- package/dist/commonjs/function-builder.d.ts +76 -5
- package/dist/commonjs/function-builder.d.ts.map +1 -1
- package/dist/commonjs/function-builder.js +56 -2
- package/dist/commonjs/function-builder.js.map +1 -1
- package/dist/commonjs/index.d.ts +1 -0
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +4 -1
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/invoke-on-deploy.d.ts +83 -0
- package/dist/commonjs/invoke-on-deploy.d.ts.map +1 -0
- package/dist/commonjs/invoke-on-deploy.js +155 -0
- package/dist/commonjs/invoke-on-deploy.js.map +1 -0
- package/dist/esm/function-builder.d.ts +76 -5
- package/dist/esm/function-builder.d.ts.map +1 -1
- package/dist/esm/function-builder.js +57 -3
- package/dist/esm/function-builder.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/invoke-on-deploy.d.ts +83 -0
- package/dist/esm/invoke-on-deploy.d.ts.map +1 -0
- package/dist/esm/invoke-on-deploy.js +151 -0
- package/dist/esm/invoke-on-deploy.js.map +1 -0
- package/package.json +3 -12
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { Annotations, Duration } from "aws-cdk-lib";
|
|
2
|
+
import { InvocationType, Trigger } from "aws-cdk-lib/triggers";
|
|
3
|
+
import { addDependencies } from "@composurecdk/core";
|
|
4
|
+
/**
|
|
5
|
+
* Suppression id for the deploy-time invocation timeout guard. Stable and part
|
|
6
|
+
* of the public surface — silence the warning with
|
|
7
|
+
* `Annotations.of(scope).acknowledgeWarning(INVOKE_ON_DEPLOY_TIMEOUT_WARNING_ID)`,
|
|
8
|
+
* so it must not be renamed casually.
|
|
9
|
+
*/
|
|
10
|
+
export const INVOKE_ON_DEPLOY_TIMEOUT_WARNING_ID = "@composurecdk/lambda:invoke-on-deploy-timeout";
|
|
11
|
+
/**
|
|
12
|
+
* The deployment waits for the handler's response, so a handler that throws
|
|
13
|
+
* fails the stack. An invariant of the action rather than a default: the
|
|
14
|
+
* asynchronous alternative returns before the work happens, reporting success
|
|
15
|
+
* whatever the handler did, so there is nothing to override to.
|
|
16
|
+
*
|
|
17
|
+
* @see https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/rel_tracking_change_management_deployment_management.html
|
|
18
|
+
*/
|
|
19
|
+
const INVOCATION_TYPE = InvocationType.REQUEST_RESPONSE;
|
|
20
|
+
/**
|
|
21
|
+
* The trigger provider's own Lambda timeout. CDK builds that provider from
|
|
22
|
+
* `CustomResourceProviderBase`, which defaults to 15 minutes, and `Trigger`
|
|
23
|
+
* overrides nothing — so there is no seam to raise it through and no way to
|
|
24
|
+
* read it back. Asserted against a synthesised template in the test suite, so
|
|
25
|
+
* an `aws-cdk-lib` upgrade that changes the default fails loudly here rather
|
|
26
|
+
* than quietly reopening the hang this ceiling exists to prevent.
|
|
27
|
+
*/
|
|
28
|
+
const PROVIDER_TIMEOUT = Duration.minutes(15);
|
|
29
|
+
/**
|
|
30
|
+
* Added to the function's own `timeout` to derive the wait, and subtracted
|
|
31
|
+
* from {@link PROVIDER_TIMEOUT} to derive {@link MAX_TIMEOUT} — the same slack
|
|
32
|
+
* at both ends, for the same reason: whoever is waiting must outlive whoever
|
|
33
|
+
* they are waiting for, or the error is never reported.
|
|
34
|
+
*/
|
|
35
|
+
const TIMEOUT_MARGIN = Duration.seconds(30);
|
|
36
|
+
/**
|
|
37
|
+
* Ceiling for the wait. The provider must outlive the invocation it is waiting
|
|
38
|
+
* on, or it dies mid-wait and posts nothing back to CloudFormation. `Trigger`
|
|
39
|
+
* sets no `ServiceTimeout` on the custom resource, so that is not a failed
|
|
40
|
+
* deployment — it is a *hung* one, until CloudFormation abandons the stack
|
|
41
|
+
* operation of its own accord.
|
|
42
|
+
*/
|
|
43
|
+
const MAX_TIMEOUT = PROVIDER_TIMEOUT.minus(TIMEOUT_MARGIN);
|
|
44
|
+
/**
|
|
45
|
+
* The wait applied when the function's own timeout is unset or a token, and so
|
|
46
|
+
* yields no concrete value to derive from. Matches the CDK `Trigger` default.
|
|
47
|
+
*/
|
|
48
|
+
const FALLBACK_TIMEOUT = Duration.minutes(2);
|
|
49
|
+
/**
|
|
50
|
+
* How {@link IFunctionBuilder.invokeOnDeploy | `.invokeOnDeploy()`} derives the
|
|
51
|
+
* wait when the caller sets no {@link InvokeOnDeployOptions.timeout}. A public
|
|
52
|
+
* mirror of this module's constants, exported for visibility and testing — the
|
|
53
|
+
* rationale for each value is on the constant it mirrors.
|
|
54
|
+
*/
|
|
55
|
+
export const INVOKE_ON_DEPLOY_DEFAULTS = {
|
|
56
|
+
/** @see {@link TIMEOUT_MARGIN} */
|
|
57
|
+
timeoutMargin: TIMEOUT_MARGIN,
|
|
58
|
+
/** @see {@link FALLBACK_TIMEOUT} */
|
|
59
|
+
fallbackTimeout: FALLBACK_TIMEOUT,
|
|
60
|
+
/** @see {@link MAX_TIMEOUT} */
|
|
61
|
+
maxTimeout: MAX_TIMEOUT,
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Creates the custom resource that invokes `handler` during deployment and
|
|
65
|
+
* fails the stack if it errors.
|
|
66
|
+
*
|
|
67
|
+
* The invocation is ordered after the function's execution role, so the policies
|
|
68
|
+
* attached *to it* by `.grant()` / `.configureRole()` — which CloudFormation
|
|
69
|
+
* does not otherwise sequence ahead of a custom resource — exist by the time the
|
|
70
|
+
* handler runs.
|
|
71
|
+
*
|
|
72
|
+
* That reaches the identity half of a grant only: one that also writes a
|
|
73
|
+
* resource policy (a KMS key policy, a cross-account bucket policy) leaves that
|
|
74
|
+
* half in the granting resource's tree, and an imported role contributes no
|
|
75
|
+
* resources to sequence at all. Both are the consumer's to declare through
|
|
76
|
+
* {@link InvokeOnDeployOptions.after}, as is anything else the call needs.
|
|
77
|
+
*
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
export function createDeploymentTrigger(scope, id, handler, executionRole, options, context) {
|
|
81
|
+
const timeout = resolveWait(options.timeout, handler.timeout, id);
|
|
82
|
+
warnOnShortWait(handler, id, timeout);
|
|
83
|
+
const trigger = new Trigger(scope, `${id}DeploymentTrigger`, {
|
|
84
|
+
handler,
|
|
85
|
+
invocationType: INVOCATION_TYPE,
|
|
86
|
+
timeout,
|
|
87
|
+
executeOnHandlerChange: options.executeOnHandlerChange,
|
|
88
|
+
});
|
|
89
|
+
addDependencies(trigger, [executionRole, ...(options.after ?? [])], context);
|
|
90
|
+
return trigger;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* How long the deployment waits.
|
|
94
|
+
*
|
|
95
|
+
* {@link MAX_TIMEOUT} binds both branches, but differently. A derived wait is
|
|
96
|
+
* capped: the derivation is the library's, so quietly settling for less than it
|
|
97
|
+
* wanted is the library's business. An explicit wait over the ceiling throws —
|
|
98
|
+
* clamping would honour neither the duration the caller asked for nor the
|
|
99
|
+
* failing deployment they expected, and there is no working form to fall back
|
|
100
|
+
* to. Both are silent on a token, which has no value to compare.
|
|
101
|
+
*/
|
|
102
|
+
function resolveWait(explicitWait, handlerTimeout, id) {
|
|
103
|
+
if (explicitWait !== undefined) {
|
|
104
|
+
const waitSeconds = concreteSeconds(explicitWait);
|
|
105
|
+
if (waitSeconds !== undefined && waitSeconds > MAX_TIMEOUT.toSeconds()) {
|
|
106
|
+
throw new Error(`FunctionBuilder "${id}": .invokeOnDeploy() was given a timeout of ${String(waitSeconds)}s, ` +
|
|
107
|
+
`but the deployment cannot wait longer than ${String(MAX_TIMEOUT.toSeconds())}s — CDK's ` +
|
|
108
|
+
`trigger provider runs with a ${String(PROVIDER_TIMEOUT.toSeconds())}s Lambda timeout ` +
|
|
109
|
+
`and needs the remainder to report the result. A longer wait does not fail the ` +
|
|
110
|
+
`deployment, it hangs it: the provider dies mid-invocation and CloudFormation is never ` +
|
|
111
|
+
`told. Lower the timeout, or move work that needs longer out of the deployment.`);
|
|
112
|
+
}
|
|
113
|
+
return explicitWait;
|
|
114
|
+
}
|
|
115
|
+
const handlerSeconds = concreteSeconds(handlerTimeout);
|
|
116
|
+
if (handlerSeconds === undefined)
|
|
117
|
+
return FALLBACK_TIMEOUT;
|
|
118
|
+
const derived = handlerSeconds + TIMEOUT_MARGIN.toSeconds();
|
|
119
|
+
return Duration.seconds(Math.min(derived, MAX_TIMEOUT.toSeconds()));
|
|
120
|
+
}
|
|
121
|
+
/** A `Duration` in seconds, or `undefined` when it is unset or a token. */
|
|
122
|
+
function concreteSeconds(duration) {
|
|
123
|
+
if (duration === undefined || duration.isUnresolved())
|
|
124
|
+
return undefined;
|
|
125
|
+
return duration.toSeconds();
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Warns when the deployment would stop waiting before the handler's own timeout
|
|
129
|
+
* — a handler that runs long then fails the stack as an abandoned invocation
|
|
130
|
+
* rather than reporting the error it was about to produce.
|
|
131
|
+
*
|
|
132
|
+
* Checked against the final wait, whether the caller set it or it was derived,
|
|
133
|
+
* because the derived path can land here too: the cap leaves no margin once the
|
|
134
|
+
* function's own timeout reaches {@link MAX_TIMEOUT}.
|
|
135
|
+
* Silent whenever either value is a token, with nothing to compare.
|
|
136
|
+
*/
|
|
137
|
+
function warnOnShortWait(handler, id, wait) {
|
|
138
|
+
const waitSeconds = concreteSeconds(wait);
|
|
139
|
+
const handlerSeconds = concreteSeconds(handler.timeout);
|
|
140
|
+
if (waitSeconds === undefined || handlerSeconds === undefined)
|
|
141
|
+
return;
|
|
142
|
+
if (waitSeconds > handlerSeconds)
|
|
143
|
+
return;
|
|
144
|
+
Annotations.of(handler).addWarningV2(INVOKE_ON_DEPLOY_TIMEOUT_WARNING_ID, `FunctionBuilder "${id}": .invokeOnDeploy() waits ${String(waitSeconds)}s but the function's ` +
|
|
145
|
+
`own timeout is ${String(handlerSeconds)}s — the deployment stops waiting while the handler ` +
|
|
146
|
+
`is still running, so a slow call fails the stack as an abandoned invocation instead of ` +
|
|
147
|
+
`reporting the handler's error. Give the deployment longer than the function's timeout (up ` +
|
|
148
|
+
`to ${String(MAX_TIMEOUT.toSeconds())}s), shorten the function's ` +
|
|
149
|
+
`timeout, or acknowledge "${INVOKE_ON_DEPLOY_TIMEOUT_WARNING_ID}".`);
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=invoke-on-deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invoke-on-deploy.js","sourceRoot":"","sources":["../../src/invoke-on-deploy.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@composurecdk/lambda",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Composable Lambda function builder with well-architected defaults",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -12,15 +12,6 @@
|
|
|
12
12
|
"README.md",
|
|
13
13
|
"LICENSE"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"lint": "eslint .",
|
|
17
|
-
"clean": "rm -rf dist .tshy .tshy-build",
|
|
18
|
-
"build": "tshy",
|
|
19
|
-
"typecheck": "tsc --noEmit",
|
|
20
|
-
"check:exports": "attw --pack . --profile node16 && publint",
|
|
21
|
-
"test": "vitest run --passWithNoTests",
|
|
22
|
-
"test:watch": "vitest"
|
|
23
|
-
},
|
|
24
15
|
"keywords": [
|
|
25
16
|
"aws",
|
|
26
17
|
"cdk",
|
|
@@ -59,8 +50,8 @@
|
|
|
59
50
|
"devDependencies": {
|
|
60
51
|
"@composurecdk/cdk-testing": "*",
|
|
61
52
|
"@composurecdk/iam": "^0.10.0",
|
|
62
|
-
"@types/node": "^26.
|
|
63
|
-
"aws-cdk-lib": "^2.
|
|
53
|
+
"@types/node": "^26.6.1",
|
|
54
|
+
"aws-cdk-lib": "^2.269.0",
|
|
64
55
|
"constructs": "^10.8.1",
|
|
65
56
|
"ts-fake": "^1.2.0",
|
|
66
57
|
"typescript": "^6.0.3",
|