@go-to-k/cdkd 0.284.24 → 0.284.26
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/dist/{asg-provider-Bh0odlSk.js → asg-provider-CS5j-5z6.js} +2 -2
- package/dist/{asg-provider-Bh0odlSk.js.map → asg-provider-CS5j-5z6.js.map} +1 -1
- package/dist/cli.js +521 -176
- package/dist/cli.js.map +1 -1
- package/dist/{deploy-engine-BJQbni1s.js → deploy-engine-DNCs229s.js} +294 -34
- package/dist/deploy-engine-DNCs229s.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/deploy-engine-BJQbni1s.js.map +0 -1
|
@@ -6838,6 +6838,19 @@ var S3StateBackend = class {
|
|
|
6838
6838
|
* but `--state-prefix` overrides at the consumer side propagate
|
|
6839
6839
|
* cleanly).
|
|
6840
6840
|
*/
|
|
6841
|
+
/**
|
|
6842
|
+
* Release the S3 client this backend currently holds.
|
|
6843
|
+
*
|
|
6844
|
+
* The backend OWNS its client and may destroy and REPLACE it
|
|
6845
|
+
* (`ensureClientForBucket` rebuilds when the bucket turns out to live in
|
|
6846
|
+
* another region). So a caller that keeps its own reference and destroys
|
|
6847
|
+
* that instead destroys the dead original and leaks the live replacement —
|
|
6848
|
+
* which is exactly what a short-lived probe backend does in the cross-region
|
|
6849
|
+
* case. Callers that construct a throwaway backend use this instead.
|
|
6850
|
+
*/
|
|
6851
|
+
destroyClient() {
|
|
6852
|
+
this.s3Client.destroy();
|
|
6853
|
+
}
|
|
6841
6854
|
get prefix() {
|
|
6842
6855
|
return this.config.prefix;
|
|
6843
6856
|
}
|
|
@@ -16860,7 +16873,7 @@ var CloudControlProvider = class {
|
|
|
16860
16873
|
if (context?.finalSnapshotIdentifier !== void 0) throw new ProvisioningError(`${logicalId} (${resourceType}) requires a final snapshot (DeletionPolicy: Snapshot), but the Cloud Control API delete route has no final-snapshot parameter. Re-run with --skip-final-snapshot after snapshotting manually, or retain the resource.`, resourceType, logicalId, physicalId);
|
|
16861
16874
|
if (context?.removeProtection === true && resourceType === "AWS::AutoScaling::AutoScalingGroup") {
|
|
16862
16875
|
this.logger.debug(`Delegating protected AutoScalingGroup ${logicalId} delete to the SDK ASGProvider (Cloud Control cannot force-delete a protected ASG)`);
|
|
16863
|
-
const { ASGProvider } = await import("./asg-provider-
|
|
16876
|
+
const { ASGProvider } = await import("./asg-provider-CS5j-5z6.js").then((n) => n.n);
|
|
16864
16877
|
return await new ASGProvider().delete(logicalId, physicalId, resourceType, _properties, context);
|
|
16865
16878
|
}
|
|
16866
16879
|
const isProtectedEc2Instance = context?.removeProtection === true && resourceType === "AWS::EC2::Instance";
|
|
@@ -17531,6 +17544,280 @@ var CloudControlProvider = class {
|
|
|
17531
17544
|
}
|
|
17532
17545
|
};
|
|
17533
17546
|
|
|
17547
|
+
//#endregion
|
|
17548
|
+
//#region src/provisioning/interrupt-watch.ts
|
|
17549
|
+
/**
|
|
17550
|
+
* The ONE interrupt watch every bounded wait under `src/provisioning/**` uses
|
|
17551
|
+
* (issues #2053 / #1952, consolidating the per-invocation shape PR #2033
|
|
17552
|
+
* introduced in `providers/custom-resource-provider.ts`).
|
|
17553
|
+
*
|
|
17554
|
+
* WHY A WAIT NEEDS ONE AT ALL
|
|
17555
|
+
* ---------------------------
|
|
17556
|
+
* `withRetry` (`src/deployment/retry.ts`) is the only wait in cdkd that
|
|
17557
|
+
* consults an interrupt DURING a backoff — it probes once a second while
|
|
17558
|
+
* sleeping. The deploy engine, `destroy-runner.ts` and `rollback-executor.ts`
|
|
17559
|
+
* all poll only BETWEEN operations. So a retry that threads nothing is dead to
|
|
17560
|
+
* Ctrl-C for its whole schedule, and on the destroy path `withResourceTimeout`
|
|
17561
|
+
* has by then abandoned the promise WITHOUT cancelling it, so the loop keeps
|
|
17562
|
+
* issuing writes behind a run the user was told had ended.
|
|
17563
|
+
* `docs/provider-development.md` states the requirement; `vp run
|
|
17564
|
+
* audit:withretry-interrupt:check` enforces it.
|
|
17565
|
+
*
|
|
17566
|
+
* WHY IT IS SHARED RATHER THAN PER MODULE
|
|
17567
|
+
* ---------------------------------------
|
|
17568
|
+
* Four modules carried a copy before issue #2104, and the copies could not
|
|
17569
|
+
* agree about the one thing that matters: a single `delete()` traverses more
|
|
17570
|
+
* than one of them, so a SIGINT marked only whichever module happened to hold a
|
|
17571
|
+
* live watch. One module means one latch, one error type, and ONE process
|
|
17572
|
+
* listener rather than four.
|
|
17573
|
+
*
|
|
17574
|
+
* FOUR PROPERTIES, EACH LOAD-BEARING
|
|
17575
|
+
* ----------------------------------
|
|
17576
|
+
*
|
|
17577
|
+
* 1. **The flag is per WAIT, never on a provider.** Providers are registered as
|
|
17578
|
+
* SINGLETONS serving concurrent resources, so provider-level state is some
|
|
17579
|
+
* other resource's.
|
|
17580
|
+
*
|
|
17581
|
+
* 2. **The latch is STICKY.** A watch STARTED after the signal begins is
|
|
17582
|
+
* already interrupted. Clearing it when the last watch is disposed — the
|
|
17583
|
+
* first cut — is wrong for exactly the case issue #1952 is about: a
|
|
17584
|
+
* `GlobalTable` delete runs the #1521 gate, then the index-busy retry loop,
|
|
17585
|
+
* then the gone-wait, each disposing before the next begins, so a SIGINT
|
|
17586
|
+
* during the gate left the two multi-minute waits after it DEAF. Only a
|
|
17587
|
+
* COMMAND clears it. The listener is likewise never torn down BETWEEN two
|
|
17588
|
+
* waits: one removed in that gap cannot record a signal landing in it, which
|
|
17589
|
+
* is the same bug one layer down. {@link endCommandInterruptScope} removes it
|
|
17590
|
+
* at command END, where there is no next wait to miss.
|
|
17591
|
+
*
|
|
17592
|
+
* 3. **It arms only inside a command that OWNS interrupt handling.** Registering
|
|
17593
|
+
* any SIGINT listener disables Node's default terminate, so a command with no
|
|
17594
|
+
* graceful shutdown of its own must not gain one here: `cdkd drift --revert`
|
|
17595
|
+
* reaches `provider.update` and installs nothing, and an armed watch there
|
|
17596
|
+
* would leave Ctrl-C setting flags nobody reads while the command carried on
|
|
17597
|
+
* writing to AWS — needing a SIGKILL.
|
|
17598
|
+
*
|
|
17599
|
+
* The gate is an explicit flag raised by
|
|
17600
|
+
* {@link beginCommandInterruptScope}, which `forwardSigtermToSigint()` calls
|
|
17601
|
+
* at command start. It is deliberately NOT
|
|
17602
|
+
* `process.listenerCount('SIGINT') > 0`, which was the first cut and is
|
|
17603
|
+
* defeated by the very case it was meant to catch: `cdkd drift` runs
|
|
17604
|
+
* `provider.update` at concurrency 4, and a concurrent CloudFront / ACM /
|
|
17605
|
+
* Route53 wait installs a TRANSIENT SIGINT listener of its own — so an ELBv2
|
|
17606
|
+
* update starting inside that window saw a non-zero count, armed, and then
|
|
17607
|
+
* kept the listener for the rest of the command after the transient one was
|
|
17608
|
+
* removed. A count answers "is anyone listening right now"; the question is
|
|
17609
|
+
* "does this COMMAND have a shutdown path", and only the command can say.
|
|
17610
|
+
* (`forwardSigtermToSigint` itself registers on SIGTERM only, so it never
|
|
17611
|
+
* satisfied the count either — a detail an earlier version of this comment
|
|
17612
|
+
* got wrong, which is how the gap survived a review.)
|
|
17613
|
+
*
|
|
17614
|
+
* Arming is re-attempted on every watch, so a wait that runs before the
|
|
17615
|
+
* command opens its scope does not poison later ones.
|
|
17616
|
+
*
|
|
17617
|
+
* 4. **The handler force-quits when it is the LAST listener.** Property 3 gets
|
|
17618
|
+
* the watch armed only under a command with a shutdown path, but that path
|
|
17619
|
+
* is not live for the command's whole duration: `destroy.ts` registers no
|
|
17620
|
+
* SIGINT handler of its own, and `destroy-runner.ts` removes its one in a
|
|
17621
|
+
* `finally` — so between two stacks of a multi-stack destroy the shared
|
|
17622
|
+
* handler is the ONLY listener. Merely latching there SWALLOWS the Ctrl-C:
|
|
17623
|
+
* the process does not exit, `draining` is never set, `result.interrupted`
|
|
17624
|
+
* stays false, and the loop proceeds to delete the NEXT stack after the user
|
|
17625
|
+
* asked to stop — this file's own headline failure, one layer out.
|
|
17626
|
+
*
|
|
17627
|
+
* So when no other listener remains, the handler restores exactly what Node
|
|
17628
|
+
* would have done with no listener at all. That is deliberately not a second
|
|
17629
|
+
* graceful path: inventing one would duplicate `destroy-runner.ts`'s drain
|
|
17630
|
+
* and have to be kept in sync with it, whereas "there is no graceful owner
|
|
17631
|
+
* right now, so terminate" is true by construction and needs no upkeep.
|
|
17632
|
+
*/
|
|
17633
|
+
/**
|
|
17634
|
+
* Thrown by {@link InterruptWatch.onInterrupted}, and the ONE type the whole
|
|
17635
|
+
* codebase uses to mean "a wait stopped because the user asked us to stop".
|
|
17636
|
+
*
|
|
17637
|
+
* It has to be a distinct class rather than a bare `Error` because
|
|
17638
|
+
* `deploy-engine.ts` decides whether to ROLL BACK by asking what the failure
|
|
17639
|
+
* was. Its own `InterruptedError` is module-private, so a provider cannot
|
|
17640
|
+
* produce one; a bare `Error` from a provider therefore read as a genuine
|
|
17641
|
+
* resource failure and triggered an automatic rollback of the whole stack on
|
|
17642
|
+
* Ctrl-C — strictly worse than the unresponsiveness the threading removes.
|
|
17643
|
+
*
|
|
17644
|
+
* The explicit `setPrototypeOf` is not decoration: without it a subclass of
|
|
17645
|
+
* `Error` loses `instanceof` under this repo's compile target, which would make
|
|
17646
|
+
* {@link isInterruptedWaitError} silently answer `false`.
|
|
17647
|
+
*/
|
|
17648
|
+
var InterruptedWaitError = class InterruptedWaitError extends Error {
|
|
17649
|
+
constructor(what) {
|
|
17650
|
+
super(`${what} interrupted by user (SIGINT)`);
|
|
17651
|
+
this.name = "InterruptedWaitError";
|
|
17652
|
+
Object.setPrototypeOf(this, InterruptedWaitError.prototype);
|
|
17653
|
+
}
|
|
17654
|
+
};
|
|
17655
|
+
/**
|
|
17656
|
+
* Whether `error` IS an interrupt, or WRAPS one.
|
|
17657
|
+
*
|
|
17658
|
+
* The wrap is the normal case, not the edge case: every provider catch under
|
|
17659
|
+
* `src/provisioning/providers/**` re-throws AWS failures as a
|
|
17660
|
+
* `ProvisioningError` threading the original as `cause` (issue #2040, enforced
|
|
17661
|
+
* by `vp run audit:provider-error-cause:check`), so by the time the engine sees
|
|
17662
|
+
* an interrupt it is one or more `cause` hops down. A plain `instanceof` check
|
|
17663
|
+
* at the engine would therefore have been a placebo.
|
|
17664
|
+
*
|
|
17665
|
+
* **The walk is bounded by a VISITED SET, not by a depth ceiling**, and the
|
|
17666
|
+
* difference decides correctness rather than style. A ceiling has to be sized
|
|
17667
|
+
* against the deepest real chain, and that chain GROWS: the flat case is 2 (the
|
|
17668
|
+
* provider's own wrap, then the command's), `DagExecutor` adds none — it
|
|
17669
|
+
* collects rather than wraps (`dag-executor.ts:178`) — but `deploy-engine.ts`
|
|
17670
|
+
* adds one `ProvisioningError` PER NESTED-STACK LEVEL (`deploy-engine.ts:2932`;
|
|
17671
|
+
* `NestedStackProvider.create` adds none of its own). A depth-5 cap therefore
|
|
17672
|
+
* missed at four levels of nesting, and missing here is not a degraded answer:
|
|
17673
|
+
* it is a full automatic rollback on Ctrl-C. The visited set gives the
|
|
17674
|
+
* termination the cap was really there for — a cyclic `cause` chain, which
|
|
17675
|
+
* would otherwise spin on the ERROR path where nothing else is watching —
|
|
17676
|
+
* without a ceiling any legitimate nest can cross.
|
|
17677
|
+
*/
|
|
17678
|
+
function isInterruptedWaitError(error) {
|
|
17679
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17680
|
+
let current = error;
|
|
17681
|
+
while (current !== void 0 && current !== null) {
|
|
17682
|
+
if (current instanceof InterruptedWaitError) return true;
|
|
17683
|
+
if (!(current instanceof Error)) return false;
|
|
17684
|
+
if (seen.has(current)) return false;
|
|
17685
|
+
seen.add(current);
|
|
17686
|
+
current = current.cause;
|
|
17687
|
+
}
|
|
17688
|
+
return false;
|
|
17689
|
+
}
|
|
17690
|
+
const liveWatches = /* @__PURE__ */ new Set();
|
|
17691
|
+
let sharedSigintHandler;
|
|
17692
|
+
let sigintLatched = false;
|
|
17693
|
+
/**
|
|
17694
|
+
* Test seam for the "this command owns interrupt handling" gate and for the
|
|
17695
|
+
* force-quit in property 4.
|
|
17696
|
+
*
|
|
17697
|
+
* Production never assigns either, and neither condition may be weakened to
|
|
17698
|
+
* accommodate tests: a command without a shutdown path really must keep Node's
|
|
17699
|
+
* default terminate, and a swallowed Ctrl-C in a multi-stack destroy really is
|
|
17700
|
+
* a blocker. `cdkd drift --revert` and `cdkd destroy` are the live instances.
|
|
17701
|
+
*
|
|
17702
|
+
* `commandOwnsInterrupts` exists because a provider suite never runs a COMMAND,
|
|
17703
|
+
* so every interrupt test would otherwise exercise the UNARMED path while
|
|
17704
|
+
* appearing to test the armed one — the worst of both, since it fails for a
|
|
17705
|
+
* reason unrelated to what the test claims. `forceQuit` exists because the real
|
|
17706
|
+
* one calls `process.exit`, which would take the test runner with it.
|
|
17707
|
+
*/
|
|
17708
|
+
const interruptWatchTestSeam = {};
|
|
17709
|
+
/**
|
|
17710
|
+
* How many command scopes are currently open.
|
|
17711
|
+
*
|
|
17712
|
+
* A COUNTER rather than a boolean, because a boolean is only correct while
|
|
17713
|
+
* scopes never overlap. The CLI runs one command per process so they do not
|
|
17714
|
+
* today — but this module's own contract offers itself to "a host that runs
|
|
17715
|
+
* more than one command", and under a boolean the inner scope's `end` would
|
|
17716
|
+
* remove the shared listener and clear the OUTER command's sticky latch
|
|
17717
|
+
* mid-run, so a signal landing in the re-arm gap goes unrecorded. That is
|
|
17718
|
+
* exactly what property 2 forbids, arrived at from the other direction.
|
|
17719
|
+
*/
|
|
17720
|
+
let commandInterruptScopeDepth = 0;
|
|
17721
|
+
function commandOwnsInterrupts() {
|
|
17722
|
+
const override = interruptWatchTestSeam.commandOwnsInterrupts;
|
|
17723
|
+
if (override !== void 0) return override();
|
|
17724
|
+
return commandInterruptScopeDepth > 0;
|
|
17725
|
+
}
|
|
17726
|
+
/**
|
|
17727
|
+
* Install the ONE process listener, if and only if the running command has
|
|
17728
|
+
* declared that it owns interrupt handling. See property 3 for why the "if" is
|
|
17729
|
+
* load-bearing rather than defensive.
|
|
17730
|
+
*
|
|
17731
|
+
* Called on every `startInterruptWatch` rather than once, so a wait that runs
|
|
17732
|
+
* before the command opens its interrupt scope leaves the door open instead of
|
|
17733
|
+
* latching a permanent "unarmed".
|
|
17734
|
+
*/
|
|
17735
|
+
function armSharedSigintHandler() {
|
|
17736
|
+
if (sharedSigintHandler !== void 0) return;
|
|
17737
|
+
if (!commandOwnsInterrupts()) return;
|
|
17738
|
+
const handler = () => {
|
|
17739
|
+
sigintLatched = true;
|
|
17740
|
+
for (const live of liveWatches) live.interrupted = true;
|
|
17741
|
+
if (process.listeners("SIGINT").filter((l) => l !== handler).length === 0) {
|
|
17742
|
+
process.stderr.write("\nInterrupted.\nIf the next run reports a stack lock, release it with: cdkd force-unlock <stack-name>\n");
|
|
17743
|
+
(interruptWatchTestSeam.forceQuit ?? ((code) => process.exit(code)))(130);
|
|
17744
|
+
}
|
|
17745
|
+
};
|
|
17746
|
+
sharedSigintHandler = handler;
|
|
17747
|
+
process.on("SIGINT", handler);
|
|
17748
|
+
}
|
|
17749
|
+
/**
|
|
17750
|
+
* Start a watch for ONE wait. `what` names the wait in the thrown message.
|
|
17751
|
+
*
|
|
17752
|
+
* The caller MUST `dispose()` in a `finally`. A leaked watch is not merely
|
|
17753
|
+
* untidy: it stays in {@link liveWatches} forever, and the sticky latch means
|
|
17754
|
+
* every wait after a Ctrl-C would keep aborting instantly even if the run
|
|
17755
|
+
* somehow continued.
|
|
17756
|
+
*/
|
|
17757
|
+
function startInterruptWatch(what) {
|
|
17758
|
+
armSharedSigintHandler();
|
|
17759
|
+
const state = { interrupted: sigintLatched };
|
|
17760
|
+
liveWatches.add(state);
|
|
17761
|
+
let disposed = false;
|
|
17762
|
+
return {
|
|
17763
|
+
isInterrupted: () => state.interrupted,
|
|
17764
|
+
onInterrupted: () => new InterruptedWaitError(what),
|
|
17765
|
+
dispose: () => {
|
|
17766
|
+
if (disposed) return;
|
|
17767
|
+
disposed = true;
|
|
17768
|
+
liveWatches.delete(state);
|
|
17769
|
+
}
|
|
17770
|
+
};
|
|
17771
|
+
}
|
|
17772
|
+
/**
|
|
17773
|
+
* Clear the sticky latch.
|
|
17774
|
+
*
|
|
17775
|
+
* Called by {@link beginCommandInterruptScope} and
|
|
17776
|
+
* {@link endCommandInterruptScope}, which bracket one command. On the CLI one
|
|
17777
|
+
* process runs one command, so the latch starts false regardless and those
|
|
17778
|
+
* calls are belt-and-braces; they earn their keep for a host that runs more
|
|
17779
|
+
* than one command, and for unit suites, where every test shares one process
|
|
17780
|
+
* and a simulated Ctrl-C would otherwise leak into every test after it.
|
|
17781
|
+
*
|
|
17782
|
+
* Deliberately NOT wired into `dispose()` — see property 2. That was the first
|
|
17783
|
+
* cut and it is precisely the bug: sequential waits always empty the live set
|
|
17784
|
+
* between them, so the latch cleared in every gap that mattered.
|
|
17785
|
+
*/
|
|
17786
|
+
function resetInterruptWatchLatch() {
|
|
17787
|
+
sigintLatched = false;
|
|
17788
|
+
for (const live of liveWatches) live.interrupted = false;
|
|
17789
|
+
}
|
|
17790
|
+
/**
|
|
17791
|
+
* Declare that this command owns interrupt handling, and clear the latch.
|
|
17792
|
+
*
|
|
17793
|
+
* Called by `forwardSigtermToSigint()` (`src/utils/interrupt-signals.ts`),
|
|
17794
|
+
* which every command that reaches a provider wait through a lock invokes at
|
|
17795
|
+
* start — `deploy`, `destroy`, `rollback`, `state`. A command that does NOT
|
|
17796
|
+
* call it (`cdkd drift`) keeps Node's default terminate, which is the point.
|
|
17797
|
+
*/
|
|
17798
|
+
function beginCommandInterruptScope() {
|
|
17799
|
+
commandInterruptScopeDepth += 1;
|
|
17800
|
+
if (commandInterruptScopeDepth === 1) resetInterruptWatchLatch();
|
|
17801
|
+
}
|
|
17802
|
+
/**
|
|
17803
|
+
* Close the scope — the command is done.
|
|
17804
|
+
*
|
|
17805
|
+
* Removing the shared listener HERE does not weaken property 2: what must never
|
|
17806
|
+
* happen is a teardown between two sequential WAITS, because a signal landing
|
|
17807
|
+
* in that gap would go unrecorded. At command end there is no next wait, and
|
|
17808
|
+
* leaving the listener installed would suppress default terminate for whatever
|
|
17809
|
+
* runs after.
|
|
17810
|
+
*/
|
|
17811
|
+
function endCommandInterruptScope() {
|
|
17812
|
+
commandInterruptScopeDepth = Math.max(0, commandInterruptScopeDepth - 1);
|
|
17813
|
+
if (commandInterruptScopeDepth > 0) return;
|
|
17814
|
+
if (sharedSigintHandler !== void 0) {
|
|
17815
|
+
process.removeListener("SIGINT", sharedSigintHandler);
|
|
17816
|
+
sharedSigintHandler = void 0;
|
|
17817
|
+
}
|
|
17818
|
+
resetInterruptWatchLatch();
|
|
17819
|
+
}
|
|
17820
|
+
|
|
17534
17821
|
//#endregion
|
|
17535
17822
|
//#region src/provisioning/providers/custom-resource-provider.ts
|
|
17536
17823
|
/**
|
|
@@ -18533,7 +18820,7 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
18533
18820
|
* #2054, which replaced its warn-and-continue).
|
|
18534
18821
|
*/
|
|
18535
18822
|
async invokeCustomResourceWithRetry(serviceToken, logicalId, operation, buildRequest) {
|
|
18536
|
-
const watch =
|
|
18823
|
+
const watch = startInterruptWatch(`Custom resource ${logicalId}`);
|
|
18537
18824
|
try {
|
|
18538
18825
|
const stackId = await this.resolveSyntheticStackId(logicalId);
|
|
18539
18826
|
let preDeliveryRetries = 0;
|
|
@@ -19084,33 +19371,6 @@ var CustomResourceProvider = class CustomResourceProvider {
|
|
|
19084
19371
|
return customResourceRetryDelays.sleep(ms);
|
|
19085
19372
|
}
|
|
19086
19373
|
/**
|
|
19087
|
-
* Install a SIGINT watch for one custom-resource invocation (issue #2033).
|
|
19088
|
-
*
|
|
19089
|
-
* `docs/provider-development.md` requires a new `withRetry` to thread
|
|
19090
|
-
* `isInterrupted` / `onInterrupted`, and a hand-rolled backoff to be
|
|
19091
|
-
* interruptible for the same reason: without it Ctrl-C is dead for the whole
|
|
19092
|
-
* 47.75s schedule. The provider already had the shape — `pollS3Response`
|
|
19093
|
-
* installs its own handler — so this is that pattern, lifted so the two new
|
|
19094
|
-
* wait sites share one flag and one disposal.
|
|
19095
|
-
*
|
|
19096
|
-
* The caller MUST `dispose()` in a `finally`; a leaked listener would
|
|
19097
|
-
* accumulate one per resource across a deploy.
|
|
19098
|
-
*/
|
|
19099
|
-
startInterruptWatch(logicalId) {
|
|
19100
|
-
let interrupted = false;
|
|
19101
|
-
const handler = () => {
|
|
19102
|
-
interrupted = true;
|
|
19103
|
-
};
|
|
19104
|
-
process.on("SIGINT", handler);
|
|
19105
|
-
return {
|
|
19106
|
-
isInterrupted: () => interrupted,
|
|
19107
|
-
onInterrupted: () => /* @__PURE__ */ new Error(`Custom resource ${logicalId} interrupted by user`),
|
|
19108
|
-
dispose: () => {
|
|
19109
|
-
process.removeListener("SIGINT", handler);
|
|
19110
|
-
}
|
|
19111
|
-
};
|
|
19112
|
-
}
|
|
19113
|
-
/**
|
|
19114
19374
|
* `sleep` that checks the interrupt watch at most a second apart, mirroring
|
|
19115
19375
|
* `withRetry`'s own once-per-second probe. Throws the watch's error when the
|
|
19116
19376
|
* user has hit Ctrl-C, so the retry loop unwinds instead of sitting out the
|
|
@@ -25526,7 +25786,7 @@ const FLUSH_INTERVAL_MS = 2e3;
|
|
|
25526
25786
|
const FLUSH_EVENT_THRESHOLD = 50;
|
|
25527
25787
|
/** Build-time cdkd version, with a dev fallback for non-built contexts. */
|
|
25528
25788
|
function getCdkdVersion() {
|
|
25529
|
-
return "0.284.
|
|
25789
|
+
return "0.284.26";
|
|
25530
25790
|
}
|
|
25531
25791
|
/**
|
|
25532
25792
|
* Generate a time-sortable unique run id, e.g.
|
|
@@ -26970,7 +27230,7 @@ var DeployEngine = class {
|
|
|
26970
27230
|
this.logger.warn(`Failed to save partial state before rollback: ${saveError instanceof Error ? saveError.message : String(saveError)}`);
|
|
26971
27231
|
}
|
|
26972
27232
|
let autoRollbackClean = false;
|
|
26973
|
-
if (error instanceof InterruptedError) {
|
|
27233
|
+
if (error instanceof InterruptedError || isInterruptedWaitError(error)) {
|
|
26974
27234
|
await this.writeRollbackJournalSegment(stackName, completedOperations, failedOperations, "interrupted", initialDeploy);
|
|
26975
27235
|
this.logger.info(`Partial state saved (${Object.keys(newResources).length} resources). Run deploy again to resume, 'cdkd rollback' to revert, or destroy to clean up.`);
|
|
26976
27236
|
throw error;
|
|
@@ -27740,7 +28000,7 @@ var DeployEngine = class {
|
|
|
27740
28000
|
}), logicalId, 3, 5e3, deleteProvider);
|
|
27741
28001
|
} catch (deleteError) {
|
|
27742
28002
|
const msg = deleteError instanceof Error ? deleteError.message : String(deleteError);
|
|
27743
|
-
if (msg.includes("does not exist") || msg.includes("was not found") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException") || msg.includes("ResourceNotFoundException")) this.logger.debug(`Resource ${logicalId} already deleted (${msg}), removing from state`);
|
|
28003
|
+
if (!isInterruptedWaitError(deleteError) && (msg.includes("does not exist") || msg.includes("was not found") || msg.includes("not found") || msg.includes("No policy found") || msg.includes("NoSuchEntity") || msg.includes("NotFoundException") || msg.includes("ResourceNotFoundException"))) this.logger.debug(`Resource ${logicalId} already deleted (${msg}), removing from state`);
|
|
27744
28004
|
else throw deleteError;
|
|
27745
28005
|
}
|
|
27746
28006
|
const deleteSkipped = deleteSkipReason(deleteResult);
|
|
@@ -28146,5 +28406,5 @@ var DeployEngine = class {
|
|
|
28146
28406
|
};
|
|
28147
28407
|
|
|
28148
28408
|
//#endregion
|
|
28149
|
-
export {
|
|
28150
|
-
//# sourceMappingURL=deploy-engine-
|
|
28409
|
+
export { isInterruptedWaitError as $, LocalMigrateError as $n, escapeRegExp$1 as $t, isStatefulRecreateTargetSync as A, CFN_TEMPLATE_BODY_LIMIT as An, s3BucketArn as At, collectPublishedOutputNames as B, processStackMessages as Bn, DagBuilder as Bt, createPreDeleteFinalSnapshot as C, resolveCaptureObservedState as Cn, TEMPLATE_SOURCED_RULES as Ct, makeCanonicalizePropertiesFn as D, resolveUseCdkBootstrapAssets as Dn, maskSecretsInText as Dt, unsupportedFinalSnapshotError as E, resolveStateBucketWithDefaultAndSource as En, isSingleDynamicReferenceToken as Et, gray as F, expectedOwnerParam as Fn, applyRoleArnIfSet as Ft, IAMRoleProvider as G, resetAwsClients as Gn, shouldRetainResource as Gt, isExportAliasCollision as H, resolveBucketRegion as Hn, LockManager as Ht, green as I, PARTITION_TABLE as In, DiffCalculator as It, ProviderRegistry as J, CdkdError as Jn, WorkGraph as Jt, collectInlinePolicyNamesManagedBySiblings as K, setAwsClients as Kn, AssetPublisher as Kt, red as L, canonicalizeRegion as Ln, INTRINSIC_KEYS as Lt, formatResourceLine as M, MIGRATE_TMP_PREFIX as Mn, s3BucketDualStackDomainName as Mt, bold as N, findLargeInlineResources as Nn, s3BucketRegionalDomainName as Nt, extractDeploymentEventError as O, stateBucketExistenceConfirmed as On, redactSecretsForState as Ot, cyan as P, uploadCfnTemplate as Pn, s3BucketWebsiteUrl as Pt, endCommandInterruptScope as Q, LocalInvokeBuildError as Qn, rewriteTemplateAssetReferences as Qt, yellow as R, derivePartitionAndUrlSuffix as Rn, describeTypeWithThrottleRetry as Rt, ccRoutedFinalSnapshotError as S, resolveAutoAssetStorage as Sn, STATE_SOURCED_READBACK_RULES as St, refusesFinalSnapshot as T, resolveStateBucketWithDefault as Tn, dynamicReferenceTokens as Tt, secretBearingStateKeyWarning as U, AwsClients as Un, S3StateBackend as Ut, exportAliasCollisionScrubWarning as V, clearBucketRegionCache as Vn, TemplateParser as Vt, stateKeySecretExposure as W, getAwsClients as Wn, rebuildClientForBucketRegion as Wt, findSilentDropProperties as X, DependencyError as Xn, createAssetRedirectResolver as Xt, findActionableSilentDrops as Y, ConfigError as Yn, buildAssetRedirectMap as Yt, beginCommandInterruptScope as Z, DeployCancelledError as Zn, loadPublishableAssetManifest as Zt, IMPLICIT_DELETE_DEPENDENCIES as _, Synthesizer as _n, isRetryableTransientError as _r, replayWarn as _t, DeploymentEventsStore as a, parseBootstrapMarker as an, ProvisioningError as ar, IntrinsicFunctionResolver as at, PRE_DELETE_SNAPSHOT_TYPES as b, getLegacyStateBucketName as bn, __exportAll as br, requireConfigString as bt, producerRegionsFromState as c, validateContainerRepoName as cn, StackHasActiveImportsError as cr, refStateLookupFromResource as ct, updatePartialMessage as d, formatDockerLoginError as dn, SynthesisError as dr, resolveExplicitPhysicalId as dt, stripControlChars as en, LocalStartServiceError as er, startInterruptWatch as et, updatePartialReason as f, getDockerCmd as fn, formatError as fr, assertRegionMatch as ft, maskingRetryLogger as g, getDockerImageBySourceHash as gn, isMarkedNonRetryable as gr, readConfigString as gt, withResourceDeadline as h, AssetManifestLoader as hn, withErrorHandling as hr, configStringRefusal as ht, DeploymentEventsReader as i, getBootstrapMarkerKey as in, PartialFailureError as ir, isTerminationProtectionPropagationError as it, renderStatefulReason as j, CFN_TEMPLATE_URL_LIMIT as jn, s3BucketDomainName as jt, MULTI_REGION_RECREATE_BLOCKED_TYPES as k, warnDeprecatedNoPrefixCliFlag as kn, scrubResourceRecord as kt, replayFailedOperations as l, buildDenyExternalAccessPolicy as ln, StackTerminationProtectionError as lr, WAFv2WebACLProvider as lt, deleteSkipReason as m, runDockerStreaming as mn, normalizeAwsError as mr, configBooleanRefusal as mt, DEFAULT_RESOURCE_WARN_AFTER_MS as n, BOOTSTRAP_MARKER_PREFIX as nn, MissingCdkCliError as nr, slowCcOperationTimeoutMs as nt, planFailedOps as o, readBootstrapMarkerBody as on, ResourceTimeoutError as or, cfnRefValueFromPhysicalId as ot, UNSPECIFIED_SKIP_REASON as p, runDockerForeground as pn, isCdkdError as pr, coerceCfnBoolean as pt, clearOnUpdateRemoval as q, AssetError as qn, stringifyValue as qt, DeployEngine as r, ensureAssetStorage as rn, NestedStackChildDirectDestroyError as rr, disableInstanceApiTermination as rt, planRollback as s, validateAssetBucketName as sn, ResourceUpdateNotSupportedError as sr, getAccountInfo as st, DEFAULT_RESOURCE_TIMEOUT_MS as t, AssetModeResolver as tn, LockError as tr, CloudControlProvider as tt, replayRollback as u, buildDockerImage as un, StateError as ur, normalizeAwsTagsToCfn as ut, computeImplicitDeleteEdges as v, synthesisStatusMessage as vn, isThrottlingError as vr, requireConfigArray as vt, isFinalSnapshotError as w, resolveSkipPrefix as wn, createSecretMasker as wt, buildFinalSnapshotIdentifier as x, resolveApp as xn, STATE_SOURCED_CROSS_GENERATION_RULES as xt, ATOMIC_FINAL_SNAPSHOT_TYPES as y, getDefaultStateBucketName as yn, markNonRetryable as yr, requireConfigObject as yt, collectDeclaredOutputNames as z, AssemblyReader as zn, withRetry as zt };
|
|
28410
|
+
//# sourceMappingURL=deploy-engine-DNCs229s.js.map
|