You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(deployment): retry AWS throttling that surfaces as HTTP 400 by error name
cdkd's transient-error classifier (isRetryableTransientError) only treated
HTTP 429 / 503 plus a fixed message-pattern table as retryable. Most AWS
throttles, however, surface as HTTP 400 with the throttling signal carried
only in the error code / name (e.g. SSM PutParameter rejects a burst with
ThrottlingException / "Rate exceeded. Ensure you have the high-throughput
setting enabled ..." at status 400), so cdkd's withRetry never retried them
and the deploy failed.
cdkd's event-driven DAG dispatches with no level barrier, so a wide stack at
a high --concurrency fires a large create burst that trips a per-service rate
limit; a non-deterministic subset of resources fails each run (the AWS SDK's
own 3 fast internal retries are not enough to drain the burst).
Fix: add name-based throttle detection. A new THROTTLING_ERROR_NAMES set
(mirrors @aws-sdk/service-error-classification's THROTTLING_ERROR_CODES) is
checked against the error AND its wrapped .cause chain (the original SDK error
is one cause-link deep under cdkd's ProvisioningError), with a bounded,
cycle-safe walk. A "Rate exceeded" message-pattern backstop covers the case
where the name is not reachable. cdkd's outer withRetry (1s/2s/4s/8s backoff,
deeper than the SDK's) then spreads the remaining creates out until the rate
window clears.
Adds the throttle-wide-dag failure-seeking integ (80 SSM Parameters + a
10-deep Fn::Sub chain + 10 IAM Roles + 10 SNS Topics at --concurrency 40),
which asserts the deploy succeeds, all 100 resources reach AWS, the chain is
created in DAG order, and destroy is clean with 0 orphans. The fixture's own
post-deploy assertions use the lighter per-parameter get-parameter API plus
AWS_RETRY_MODE=adaptive so they survive the same SSM rate window the test
deliberately induces (the throttle-prone describe-parameters LIST API would
otherwise rate-limit the assertion itself). 6 new unit tests cover the
name-based detection, the cause-chain walk, the message backstop, and
cycle-safety.
Copy file name to clipboardExpand all lines: docs/_generated/scenario-coverage.json
+18Lines changed: 18 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -259,6 +259,10 @@
259
259
{
260
260
"tag": "vpc-lambda-eni-release",
261
261
"description": "Lambda hyperplane ENI cleanup after DeleteFunction (5-30 min eventually consistent)."
262
+
},
263
+
{
264
+
"tag": "wide-dag-throttle-retry",
265
+
"description": "Wide (~100-resource: 80 SSM Parameters + 10 IAM Roles + 10 SNS Topics, 10-deep SSM Fn::Sub chain) single-stack burst deployed under a HIGH `--concurrency` to stress the concurrency limiter + event-driven DAG executor + throttle/retry classifier: a `TooManyRequests` / `Rate exceeded` / HTTP 429 during the burst must be RETRIED (deploy still succeeds) not fatal, the chained subset proves strict DAG ordering, and the destroy burst absorbs ~100 deletes with 0 orphans."
262
266
}
263
267
],
264
268
"fixtures": [
@@ -1161,6 +1165,13 @@
1161
1165
"stack-level-tag-propagation-multitype"
1162
1166
]
1163
1167
},
1168
+
{
1169
+
"name": "throttle-wide-dag",
1170
+
"annotated": true,
1171
+
"scenarios": [
1172
+
"wide-dag-throttle-retry"
1173
+
]
1174
+
},
1164
1175
{
1165
1176
"name": "update-policy-mutations",
1166
1177
"annotated": true,
@@ -1706,6 +1717,13 @@
1706
1717
"lambda",
1707
1718
"vpc-lambda"
1708
1719
]
1720
+
},
1721
+
{
1722
+
"scenario": "wide-dag-throttle-retry",
1723
+
"description": "Wide (~100-resource: 80 SSM Parameters + 10 IAM Roles + 10 SNS Topics, 10-deep SSM Fn::Sub chain) single-stack burst deployed under a HIGH `--concurrency` to stress the concurrency limiter + event-driven DAG executor + throttle/retry classifier: a `TooManyRequests` / `Rate exceeded` / HTTP 429 during the burst must be RETRIED (deploy still succeeds) not fatal, the chained subset proves strict DAG ordering, and the destroy burst absorbs ~100 deletes with 0 orphans.",
Copy file name to clipboardExpand all lines: docs/scenario-coverage.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
Run `vp run scenario-coverage` to regenerate.
6
6
7
-
**65 / 65 canonical scenarios** have at least one integ fixture exercising them. **132 / 151 integ fixtures** carry a `.scenarios.json` sidecar (with 0+ tags); the rest are un-annotated and contributor-reviewed below.
7
+
**66 / 66 canonical scenarios** have at least one integ fixture exercising them. **133 / 152 integ fixtures** carry a `.scenarios.json` sidecar (with 0+ tags); the rest are un-annotated and contributor-reviewed below.
8
8
9
9
## How this is computed
10
10
@@ -26,7 +26,7 @@ This report is a visibility tool, not a commit-time gate. Many cdkd fixtures leg
26
26
27
27
_None._ Every canonical scenario has at least one integ fixture tagged with it.
28
28
29
-
## Per-scenario coverage (65 scenarios)
29
+
## Per-scenario coverage (66 scenarios)
30
30
31
31
| Scenario | Description | Integ Fixture(s) |
32
32
|---|---|---|
@@ -95,6 +95,7 @@ _None._ Every canonical scenario has at least one integ fixture tagged with it.
95
95
|`update-replace-breadth`| Second-deploy property mutation exercising BOTH cdkd update paths in one stack: in-place provider.update() (S3 versioning toggle / Lambda env+memory / IAM inline-policy edit / SecurityGroup ingress add — physical id unchanged) AND replacement (S3 BucketName change per the replacement-rules registry — new physical id, old resource cleaned up). Regression net for provider update() paths + #807 replacement propagation + #809 Cloud Control write-only-property UPDATE on non-ECS types. |[`update-replace`](../tests/integration/update-replace/)|
96
96
|`vpc-lambda-cr-race`| Custom Resource invocation against a VPC Lambda mid-deploy (ENI-attach race window). |[`vpc-lambda-cr-race`](../tests/integration/vpc-lambda-cr-race/)|
97
97
|`vpc-lambda-eni-release`| Lambda hyperplane ENI cleanup after DeleteFunction (5-30 min eventually consistent). |[`bench-cdk-sample`](../tests/integration/bench-cdk-sample/)<br>[`destroy-interrupt`](../tests/integration/destroy-interrupt/)<br>[`lambda`](../tests/integration/lambda/)<br>[`vpc-lambda`](../tests/integration/vpc-lambda/)|
98
+
|`wide-dag-throttle-retry`| Wide (~100-resource: 80 SSM Parameters + 10 IAM Roles + 10 SNS Topics, 10-deep SSM Fn::Sub chain) single-stack burst deployed under a HIGH `--concurrency` to stress the concurrency limiter + event-driven DAG executor + throttle/retry classifier: a `TooManyRequests` / `Rate exceeded` / HTTP 429 during the burst must be RETRIED (deploy still succeeds) not fatal, the chained subset proves strict DAG ordering, and the destroy burst absorbs ~100 deletes with 0 orphans. |[`throttle-wide-dag`](../tests/integration/throttle-wide-dag/)|
// ---- Multi-resource / broad-regression set ----
211
211
'cross-cutting-deploy-destroy':
212
212
'Broad real-AWS regression set (39+ resource VPC+NAT+CF+Lambda+SQS or comparable breadth). Refreshes the integ-broad gate.',
213
+
'wide-dag-throttle-retry':
214
+
'Wide (~100-resource: 80 SSM Parameters + 10 IAM Roles + 10 SNS Topics, 10-deep SSM Fn::Sub chain) single-stack burst deployed under a HIGH `--concurrency` to stress the concurrency limiter + event-driven DAG executor + throttle/retry classifier: a `TooManyRequests` / `Rate exceeded` / HTTP 429 during the burst must be RETRIED (deploy still succeeds) not fatal, the chained subset proves strict DAG ordering, and the destroy burst absorbs ~100 deletes with 0 orphans.',
0 commit comments