@go-to-k/cdkd 0.27.0 → 0.28.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.
Binary file
package/dist/index.js CHANGED
@@ -921,8 +921,9 @@ var ResourceTimeoutError = class _ResourceTimeoutError extends CdkdError {
921
921
  super(
922
922
  `Resource ${logicalId} (${resourceType}) in ${region} timed out after ${timeoutLabel} during ${operation} (elapsed ${elapsedLabel}).
923
923
  This may indicate a stuck Cloud Control polling loop, hung Custom Resource, or
924
- slow ENI provisioning. Re-run with --resource-timeout 1h if the resource genuinely
925
- needs more time, or --verbose to see the underlying provider activity.`,
924
+ slow ENI provisioning. Re-run with --resource-timeout ${resourceType}=<DURATION>
925
+ to bump the budget for this resource type only, or --verbose to see the
926
+ underlying provider activity.`,
926
927
  "RESOURCE_TIMEOUT"
927
928
  );
928
929
  this.logicalId = logicalId;
@@ -6696,6 +6697,23 @@ var CustomResourceProvider = class _CustomResourceProvider {
6696
6697
  logger = getLogger().child("CustomResourceProvider");
6697
6698
  responseBucket;
6698
6699
  responsePrefix;
6700
+ /**
6701
+ * Opt out of the deploy engine's outer transient-error retry loop.
6702
+ *
6703
+ * The loop re-invokes `provider.create()` from the top on a transient
6704
+ * SDK error (IAM propagation, HTTP 429/503, etc.). Each invocation
6705
+ * generates a brand-new RequestId and a brand-new pre-signed S3
6706
+ * response URL via `prepareInvocation()`. If the underlying Lambda has
6707
+ * already started — e.g. an outer retry fired between the placeholder
6708
+ * `PutObject` and the `Invoke`, or after the `Invoke` returned but a
6709
+ * spurious downstream error fired — the first attempt's Lambda
6710
+ * response lands at an S3 key that nobody polls, hanging the deploy
6711
+ * until the polling timeout. The provider already polls with its own
6712
+ * exponential backoff for async patterns (CDK Provider framework with
6713
+ * isCompleteHandler), so an outer retry adds nothing but the multi-
6714
+ * key bug.
6715
+ */
6716
+ disableOuterRetry = true;
6699
6717
  /** Max time to wait for synchronous S3 response after Lambda invocation (30 seconds) */
6700
6718
  SYNC_RESPONSE_TIMEOUT_MS = 3e4;
6701
6719
  /** Max time to wait for async S3 response (CDK Provider framework with isCompleteHandler) */
@@ -6715,6 +6733,22 @@ var CustomResourceProvider = class _CustomResourceProvider {
6715
6733
  this.responsePrefix = config?.responsePrefix ?? "custom-resource-responses";
6716
6734
  this.asyncResponseTimeoutMs = config?.asyncResponseTimeoutMs ?? _CustomResourceProvider.DEFAULT_ASYNC_RESPONSE_TIMEOUT_MS;
6717
6735
  }
6736
+ /**
6737
+ * Self-reported minimum per-resource timeout.
6738
+ *
6739
+ * Custom Resource async invocations (CDK Provider framework with
6740
+ * `isCompleteHandler`) poll for up to `asyncResponseTimeoutMs`
6741
+ * (default 1 hour, matching CDK's `totalTimeout` default). The deploy
6742
+ * engine's global `--resource-timeout` default is 30 minutes, which
6743
+ * would abort a perfectly healthy CR mid-poll. By self-reporting the
6744
+ * polling cap, the engine lifts the deadline to `max(self-report,
6745
+ * global)` for CR resources only; a user-supplied per-type override
6746
+ * (`--resource-timeout AWS::CloudFormation::CustomResource=5m`) still
6747
+ * wins for explicit escape-hatching.
6748
+ */
6749
+ getMinResourceTimeoutMs() {
6750
+ return this.asyncResponseTimeoutMs;
6751
+ }
6718
6752
  /**
6719
6753
  * Set the S3 bucket for custom resource responses
6720
6754
  * Called by ProviderRegistry when state bucket is configured
@@ -8888,8 +8922,11 @@ var DeployEngine = class {
8888
8922
  const baseLabel = `${verb} ${logicalId} (${resourceType})`;
8889
8923
  renderer.addTask(logicalId, baseLabel);
8890
8924
  const operationKind = change.changeType === "CREATE" ? "CREATE" : change.changeType === "DELETE" ? "DELETE" : "UPDATE";
8925
+ const provider = this.providerRegistry.getProvider(resourceType);
8926
+ const providerMinTimeoutMs = provider.getMinResourceTimeoutMs?.() ?? 0;
8891
8927
  const warnAfterMs = this.options.resourceWarnAfterByType?.[resourceType] ?? this.options.resourceWarnAfterMs ?? DEFAULT_RESOURCE_WARN_AFTER_MS;
8892
- const timeoutMs = this.options.resourceTimeoutByType?.[resourceType] ?? this.options.resourceTimeoutMs ?? DEFAULT_RESOURCE_TIMEOUT_MS;
8928
+ const globalTimeoutMs = this.options.resourceTimeoutMs ?? DEFAULT_RESOURCE_TIMEOUT_MS;
8929
+ const timeoutMs = this.options.resourceTimeoutByType?.[resourceType] ?? Math.max(providerMinTimeoutMs, globalTimeoutMs);
8893
8930
  try {
8894
8931
  await withResourceDeadline(
8895
8932
  async () => {
@@ -8968,7 +9005,10 @@ var DeployEngine = class {
8968
9005
  const { provider: createProvider, properties: createProps } = this.selectProviderWithSafetyNet(provider, resourceType, resolvedProps, logicalId);
8969
9006
  const result = await this.withRetry(
8970
9007
  () => createProvider.create(logicalId, resourceType, createProps),
8971
- logicalId
9008
+ logicalId,
9009
+ void 0,
9010
+ void 0,
9011
+ provider
8972
9012
  );
8973
9013
  const dependencies = this.extractAllDependencies(template, logicalId);
8974
9014
  stateResources[logicalId] = {
@@ -9022,7 +9062,10 @@ var DeployEngine = class {
9022
9062
  const { provider: replaceProvider, properties: replaceProps } = this.selectProviderWithSafetyNet(provider, resourceType, resolvedProps, logicalId);
9023
9063
  const createResult = await this.withRetry(
9024
9064
  () => replaceProvider.create(logicalId, resourceType, replaceProps),
9025
- logicalId
9065
+ logicalId,
9066
+ void 0,
9067
+ void 0,
9068
+ provider
9026
9069
  );
9027
9070
  const updateReplacePolicy = template?.Resources?.[logicalId]?.UpdateReplacePolicy;
9028
9071
  if (updateReplacePolicy === "Retain") {
@@ -9073,7 +9116,10 @@ var DeployEngine = class {
9073
9116
  updateProps,
9074
9117
  currentProps
9075
9118
  ),
9076
- logicalId
9119
+ logicalId,
9120
+ void 0,
9121
+ void 0,
9122
+ provider
9077
9123
  );
9078
9124
  } catch (updateError) {
9079
9125
  const msg = updateError instanceof Error ? updateError.message : String(updateError);
@@ -9102,7 +9148,10 @@ var DeployEngine = class {
9102
9148
  const { provider: replProvider, properties: replProps } = this.selectProviderWithSafetyNet(provider, resourceType, resolvedProps, logicalId);
9103
9149
  const createResult = await this.withRetry(
9104
9150
  () => replProvider.create(logicalId, resourceType, replProps),
9105
- logicalId
9151
+ logicalId,
9152
+ void 0,
9153
+ void 0,
9154
+ provider
9106
9155
  );
9107
9156
  result = {
9108
9157
  physicalId: createResult.physicalId,
@@ -9159,7 +9208,8 @@ var DeployEngine = class {
9159
9208
  logicalId,
9160
9209
  3,
9161
9210
  // fewer retries for DELETE
9162
- 5e3
9211
+ 5e3,
9212
+ provider
9163
9213
  );
9164
9214
  } catch (deleteError) {
9165
9215
  const msg = deleteError instanceof Error ? deleteError.message : String(deleteError);
@@ -9336,8 +9386,18 @@ var DeployEngine = class {
9336
9386
  * Thin wrapper over `withRetry` from ./retry.js that injects this engine's
9337
9387
  * SIGINT-aware interrupt check and logger. The actual backoff schedule
9338
9388
  * lives there.
9389
+ *
9390
+ * When the provider opts out via `disableOuterRetry`, the operation is
9391
+ * invoked exactly once and the retry loop is skipped entirely. The
9392
+ * Custom Resource provider uses this to avoid re-running its `create()`
9393
+ * — each invocation derives a fresh pre-signed S3 URL and RequestId,
9394
+ * so an outer retry leaves the previous attempt's Lambda response
9395
+ * stranded at an S3 key nobody polls.
9339
9396
  */
9340
- async withRetry(operation, logicalId, maxRetries, initialDelayMs) {
9397
+ async withRetry(operation, logicalId, maxRetries, initialDelayMs, provider) {
9398
+ if (provider?.disableOuterRetry) {
9399
+ return operation();
9400
+ }
9341
9401
  return withRetry(operation, logicalId, {
9342
9402
  ...maxRetries !== void 0 && { maxRetries },
9343
9403
  ...initialDelayMs !== void 0 && { initialDelayMs },