@cat-factory/integrations 0.119.0 → 0.120.1
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/modules/environments/EnvironmentTeardownService.d.ts +38 -3
- package/dist/modules/environments/EnvironmentTeardownService.d.ts.map +1 -1
- package/dist/modules/environments/EnvironmentTeardownService.js +32 -4
- package/dist/modules/environments/EnvironmentTeardownService.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,9 +1,26 @@
|
|
|
1
|
-
import type { Clock } from '@cat-factory/kernel';
|
|
2
|
-
import type { EnvironmentRegistryRepository } from '@cat-factory/kernel';
|
|
1
|
+
import type { Clock, Logger, ProvisioningOutcome } from '@cat-factory/kernel';
|
|
2
|
+
import type { EnvironmentRecord, EnvironmentRegistryRepository } from '@cat-factory/kernel';
|
|
3
3
|
import type { SecretCipher } from '@cat-factory/kernel';
|
|
4
4
|
import type { EnvironmentHandle } from '@cat-factory/kernel';
|
|
5
5
|
import type { EnvironmentConnectionService } from './EnvironmentConnectionService.js';
|
|
6
6
|
import type { ProvisioningLogRecorder } from '../provisioning-logs/ProvisioningLogService.js';
|
|
7
|
+
/**
|
|
8
|
+
* Notified after a teardown ATTEMPT has been recorded in the provisioning log, whether it
|
|
9
|
+
* succeeded or failed. Its one consumer today is the run's PR verification report, whose
|
|
10
|
+
* environment-lifecycle proof cannot be closed by the run itself: the TTL sweep that reclaims the
|
|
11
|
+
* environment fires long after the last step settled, so without this edge the PR says "still
|
|
12
|
+
* live" about an environment the platform destroyed on schedule.
|
|
13
|
+
*
|
|
14
|
+
* The FAILURE edge matters as much as the success one, and for the same reason. A run that has
|
|
15
|
+
* settled has no step hook left to fire, so an environment the provider refuses to reclaim would
|
|
16
|
+
* otherwise sit on the PR as "nobody has torn this down yet" rather than as the thing an operator
|
|
17
|
+
* has to go and do: the same unreachable-leg hole one state over. The hook is therefore fired
|
|
18
|
+
* from the ONE place that records the attempt, so a future third teardown path cannot forget it.
|
|
19
|
+
*
|
|
20
|
+
* Strictly best-effort and swallowed by the service: reclaiming infrastructure must never
|
|
21
|
+
* depend on a downstream bookkeeping write.
|
|
22
|
+
*/
|
|
23
|
+
export type EnvironmentTeardownRecordedHook = (record: EnvironmentRecord, outcome: ProvisioningOutcome) => Promise<void>;
|
|
7
24
|
export interface EnvironmentTeardownServiceDependencies {
|
|
8
25
|
connectionService: EnvironmentConnectionService;
|
|
9
26
|
environmentRegistryRepository: EnvironmentRegistryRepository;
|
|
@@ -11,16 +28,34 @@ export interface EnvironmentTeardownServiceDependencies {
|
|
|
11
28
|
clock: Clock;
|
|
12
29
|
/** Best-effort provisioning-event log; absent ⇒ teardown is unchanged. */
|
|
13
30
|
provisioningLog?: ProvisioningLogRecorder;
|
|
31
|
+
/** Structured logger for the best-effort hook below; absent ⇒ its failures are unreported. */
|
|
32
|
+
logger?: Logger;
|
|
14
33
|
}
|
|
15
34
|
export declare class EnvironmentTeardownService {
|
|
16
35
|
private readonly deps;
|
|
36
|
+
private readonly log;
|
|
37
|
+
/**
|
|
38
|
+
* Late-bound because the engine that consumes it is constructed AFTER this service (it is
|
|
39
|
+
* injected into the provisioning service, which the engine takes). Same shape as
|
|
40
|
+
* `setInitiativeLoop` in the composition root, and for the same reason.
|
|
41
|
+
*/
|
|
42
|
+
private teardownRecordedHook;
|
|
17
43
|
constructor(deps: EnvironmentTeardownServiceDependencies);
|
|
44
|
+
/** Late-bind the teardown-recorded notification. Unset ⇒ nothing is notified. */
|
|
45
|
+
setTeardownRecordedHook(hook: EnvironmentTeardownRecordedHook | undefined): void;
|
|
18
46
|
/** Tear down a single environment and tombstone its record. */
|
|
19
47
|
teardown(workspaceId: string, id: string): Promise<EnvironmentHandle>;
|
|
20
48
|
/** Tear down every environment whose TTL has elapsed. Returns the count swept. */
|
|
21
49
|
sweepExpired(now: number): Promise<number>;
|
|
22
50
|
private teardownRecord;
|
|
23
|
-
|
|
51
|
+
/**
|
|
52
|
+
* Append the attempt to the provisioning log and then notify, in that order and in ONE place.
|
|
53
|
+
* The ordering is what makes the notification usable: its consumer reads the log back, so a
|
|
54
|
+
* hook fired before the row landed would report the state the edge exists to correct. Keeping
|
|
55
|
+
* both here is what makes the FAILURE edge structural rather than a line someone remembered to
|
|
56
|
+
* add beside the success one.
|
|
57
|
+
*/
|
|
58
|
+
private recordTeardownAttempt;
|
|
24
59
|
private decryptFields;
|
|
25
60
|
}
|
|
26
61
|
//# sourceMappingURL=EnvironmentTeardownService.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentTeardownService.d.ts","sourceRoot":"","sources":["../../../src/modules/environments/EnvironmentTeardownService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"EnvironmentTeardownService.d.ts","sourceRoot":"","sources":["../../../src/modules/environments/EnvironmentTeardownService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAA;AAC3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAA;AAErF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gDAAgD,CAAA;AAO7F;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,+BAA+B,GAAG,CAC5C,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,mBAAmB,KACzB,OAAO,CAAC,IAAI,CAAC,CAAA;AAElB,MAAM,WAAW,sCAAsC;IACrD,iBAAiB,EAAE,4BAA4B,CAAA;IAC/C,6BAA6B,EAAE,6BAA6B,CAAA;IAC5D,YAAY,EAAE,YAAY,CAAA;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,0EAA0E;IAC1E,eAAe,CAAC,EAAE,uBAAuB,CAAA;IACzC,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,qBAAa,0BAA0B;IASzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IARjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B;;;;OAIG;IACH,OAAO,CAAC,oBAAoB,CAA6C;IAEzE,YAA6B,IAAI,EAAE,sCAAsC,EAExE;IAED,iFAAiF;IACjF,uBAAuB,CAAC,IAAI,EAAE,+BAA+B,GAAG,SAAS,GAAG,IAAI,CAE/E;IAED,+DAA+D;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAQ1E;IAED,kFAAkF;IAC5E,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa/C;YAEa,cAAc;IAqC5B;;;;;;OAMG;YACW,qBAAqB;YA2BrB,aAAa;CAK5B"}
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import { assertFound } from '@cat-factory/kernel';
|
|
1
|
+
import { assertFound, noopLogger, runBestEffort } from '@cat-factory/kernel';
|
|
2
2
|
import { recordToHandle } from './environments.logic.js';
|
|
3
3
|
export class EnvironmentTeardownService {
|
|
4
4
|
deps;
|
|
5
|
+
log;
|
|
6
|
+
/**
|
|
7
|
+
* Late-bound because the engine that consumes it is constructed AFTER this service (it is
|
|
8
|
+
* injected into the provisioning service, which the engine takes). Same shape as
|
|
9
|
+
* `setInitiativeLoop` in the composition root, and for the same reason.
|
|
10
|
+
*/
|
|
11
|
+
teardownRecordedHook;
|
|
5
12
|
constructor(deps) {
|
|
6
13
|
this.deps = deps;
|
|
14
|
+
this.log = deps.logger ?? noopLogger;
|
|
15
|
+
}
|
|
16
|
+
/** Late-bind the teardown-recorded notification. Unset ⇒ nothing is notified. */
|
|
17
|
+
setTeardownRecordedHook(hook) {
|
|
18
|
+
this.teardownRecordedHook = hook;
|
|
7
19
|
}
|
|
8
20
|
/** Tear down a single environment and tombstone its record. */
|
|
9
21
|
async teardown(workspaceId, id) {
|
|
@@ -49,14 +61,21 @@ export class EnvironmentTeardownService {
|
|
|
49
61
|
// Log the verbatim provider error before it propagates (the sweep swallows
|
|
50
62
|
// it; an on-demand teardown surfaces it). The local record is NOT tombstoned
|
|
51
63
|
// on a provider failure, matching the existing retry-next-pass behaviour.
|
|
52
|
-
await this.
|
|
64
|
+
await this.recordTeardownAttempt(record, 'failure', error instanceof Error ? error.message : String(error));
|
|
53
65
|
throw error;
|
|
54
66
|
}
|
|
55
67
|
}
|
|
56
68
|
await this.deps.environmentRegistryRepository.softDelete(record.workspaceId, record.id, this.deps.clock.now());
|
|
57
|
-
await this.
|
|
69
|
+
await this.recordTeardownAttempt(record, 'success', null);
|
|
58
70
|
}
|
|
59
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Append the attempt to the provisioning log and then notify, in that order and in ONE place.
|
|
73
|
+
* The ordering is what makes the notification usable: its consumer reads the log back, so a
|
|
74
|
+
* hook fired before the row landed would report the state the edge exists to correct. Keeping
|
|
75
|
+
* both here is what makes the FAILURE edge structural rather than a line someone remembered to
|
|
76
|
+
* add beside the success one.
|
|
77
|
+
*/
|
|
78
|
+
async recordTeardownAttempt(record, outcome, error) {
|
|
60
79
|
await this.deps.provisioningLog?.record({
|
|
61
80
|
workspaceId: record.workspaceId,
|
|
62
81
|
subsystem: 'environment',
|
|
@@ -69,6 +88,15 @@ export class EnvironmentTeardownService {
|
|
|
69
88
|
error,
|
|
70
89
|
detail: null,
|
|
71
90
|
});
|
|
91
|
+
const hook = this.teardownRecordedHook;
|
|
92
|
+
if (!hook)
|
|
93
|
+
return;
|
|
94
|
+
await runBestEffort(this.log, 'environment.teardownRecordedHook', () => hook(record, outcome), {
|
|
95
|
+
workspaceId: record.workspaceId,
|
|
96
|
+
environmentId: record.id,
|
|
97
|
+
executionId: record.executionId,
|
|
98
|
+
outcome,
|
|
99
|
+
});
|
|
72
100
|
}
|
|
73
101
|
async decryptFields(cipher) {
|
|
74
102
|
if (!cipher)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvironmentTeardownService.js","sourceRoot":"","sources":["../../../src/modules/environments/EnvironmentTeardownService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"EnvironmentTeardownService.js","sourceRoot":"","sources":["../../../src/modules/environments/EnvironmentTeardownService.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/integrations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.120.1",
|
|
4
4
|
"description": "External-system integration domain logic for the Agent Architecture Board (GitHub, documents, tasks, environments, runners).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"ai": "^7.0.47",
|
|
28
28
|
"p-map": "^7.0.6",
|
|
29
29
|
"yaml": "^2.9.0",
|
|
30
|
-
"@cat-factory/contracts": "0.
|
|
31
|
-
"@cat-factory/kernel": "0.
|
|
30
|
+
"@cat-factory/contracts": "0.219.0",
|
|
31
|
+
"@cat-factory/kernel": "0.221.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
35
|
"undici": "^8.9.0",
|
|
36
36
|
"valibot": "^1.4.2",
|
|
37
37
|
"vitest": "^4.1.10",
|
|
38
|
-
"@cat-factory/caching": "0.13.
|
|
38
|
+
"@cat-factory/caching": "0.13.7"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -b tsconfig.build.json",
|