@smarthome.exchange/integrations 0.1.0 → 0.2.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.
- package/changelog.md +9 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/classes.runtimemanager.d.ts +6 -2
- package/dist_ts/core/classes.runtimemanager.js +74 -39
- package/package.json +1 -1
- package/readme.md +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/classes.runtimemanager.ts +88 -44
package/changelog.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-08-10 - 0.2.0
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **Breaking:** fail closed on retained runtime cleanup before setup (runtime-manager)
|
|
8
|
+
- Retry pending cleanup for the requested domain before creating or replacing an integration runtime.
|
|
9
|
+
- Reject overlapping same-domain setup and destroyAll calls while setup is in progress instead of queuing them.
|
|
10
|
+
- Retain failed replacement and mismatched-runtime cleanup under the requested domain, with retryPendingCleanup(domain) and hasPendingCleanup(domain) exposing the cleanup gate.
|
|
11
|
+
|
|
3
12
|
## 2026-08-10 - 0.1.0
|
|
4
13
|
|
|
5
14
|
### Features
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@smarthome.exchange/integrations',
|
|
6
|
-
version: '0.
|
|
6
|
+
version: '0.2.0',
|
|
7
7
|
description: 'TypeScript-native device integrations for smarthome.exchange.'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSxrQ0FBa0M7SUFDeEMsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLCtEQUErRDtDQUM3RSxDQUFBIn0=
|
|
@@ -5,7 +5,8 @@ export declare class IntegrationRuntimeManager {
|
|
|
5
5
|
private readonly runtimesPendingCleanup;
|
|
6
6
|
private readonly runtimeDestructionPromises;
|
|
7
7
|
private readonly destroyedRuntimes;
|
|
8
|
-
private
|
|
8
|
+
private readonly setupDomainsInProgress;
|
|
9
|
+
private destroyAllPromise?;
|
|
9
10
|
createRuntime<TConfig>(integrationArg: BaseIntegration<TConfig>, configArg: TConfig, contextArg?: IIntegrationSetupContext): Promise<IIntegrationRuntime>;
|
|
10
11
|
setupIntegration<TConfig>(integrationArg: BaseIntegration<TConfig>, configArg: TConfig, contextArg?: IIntegrationSetupContext): Promise<IIntegrationRuntime>;
|
|
11
12
|
activateRuntime(domainArg: string, runtimeArg: IIntegrationRuntime): IIntegrationRuntime | undefined;
|
|
@@ -15,8 +16,11 @@ export declare class IntegrationRuntimeManager {
|
|
|
15
16
|
getActiveRuntime(domainArg: string): IIntegrationRuntime | undefined;
|
|
16
17
|
getRuntime(domainArg: string): IIntegrationRuntime | undefined;
|
|
17
18
|
listRuntimes(): IIntegrationRuntime[];
|
|
19
|
+
retryPendingCleanup(domainArg: string): Promise<void>;
|
|
20
|
+
hasPendingCleanup(domainArg: string): boolean;
|
|
18
21
|
writeDeviceFeature(requestArg: IDeviceFeatureWriteRequest, expectedRuntimeArg?: IIntegrationRuntime, abortSignalArg?: AbortSignal): Promise<IServiceCallResult>;
|
|
19
22
|
destroyAll(timeoutMsArg?: number): Promise<void>;
|
|
20
23
|
private withTimeout;
|
|
21
|
-
private
|
|
24
|
+
private performDestroyAll;
|
|
25
|
+
private markRuntimePendingCleanup;
|
|
22
26
|
}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { createDescriptorOnlyIntegrationError } from './classes.descriptoronlyintegration.js';
|
|
2
2
|
export class IntegrationRuntimeManager {
|
|
3
3
|
runtimes = new Map();
|
|
4
|
-
runtimesPendingCleanup = new
|
|
4
|
+
runtimesPendingCleanup = new Map();
|
|
5
5
|
runtimeDestructionPromises = new Map();
|
|
6
6
|
destroyedRuntimes = new WeakSet();
|
|
7
|
-
|
|
7
|
+
setupDomainsInProgress = new Set();
|
|
8
|
+
destroyAllPromise;
|
|
8
9
|
async createRuntime(integrationArg, configArg, contextArg = {}) {
|
|
9
10
|
if (integrationArg.status === 'descriptor-only') {
|
|
10
11
|
throw createDescriptorOnlyIntegrationError(integrationArg.domain);
|
|
11
12
|
}
|
|
13
|
+
await this.retryPendingCleanup(integrationArg.domain);
|
|
12
14
|
const runtime = await integrationArg.setup(configArg, contextArg);
|
|
13
15
|
if (runtime.domain !== integrationArg.domain) {
|
|
14
16
|
const domainError = new Error(`Integration runtime domain mismatch: expected ${integrationArg.domain}, received ${runtime.domain}`);
|
|
17
|
+
this.markRuntimePendingCleanup(integrationArg.domain, runtime);
|
|
15
18
|
try {
|
|
16
19
|
await this.destroyRuntime(runtime);
|
|
17
20
|
}
|
|
@@ -23,26 +26,26 @@ export class IntegrationRuntimeManager {
|
|
|
23
26
|
return runtime;
|
|
24
27
|
}
|
|
25
28
|
async setupIntegration(integrationArg, configArg, contextArg = {}) {
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
if (this.destroyAllPromise) {
|
|
30
|
+
throw new Error('Cannot set up an integration while destroyAll is in progress.');
|
|
31
|
+
}
|
|
32
|
+
if (this.setupDomainsInProgress.has(integrationArg.domain)) {
|
|
33
|
+
throw new Error(`Integration setup is already in progress: ${integrationArg.domain}`);
|
|
34
|
+
}
|
|
35
|
+
this.setupDomainsInProgress.add(integrationArg.domain);
|
|
36
|
+
try {
|
|
37
|
+
await this.retryPendingCleanup(integrationArg.domain);
|
|
28
38
|
const previousRuntime = this.retireRuntime(integrationArg.domain);
|
|
29
39
|
if (previousRuntime) {
|
|
30
|
-
|
|
31
|
-
await this.destroyRuntime(previousRuntime);
|
|
32
|
-
}
|
|
33
|
-
catch (destroyError) {
|
|
34
|
-
try {
|
|
35
|
-
await this.destroyRuntime(runtime);
|
|
36
|
-
}
|
|
37
|
-
catch (cleanupError) {
|
|
38
|
-
throw new AggregateError([destroyError, cleanupError], `Failed to replace integration runtime for ${integrationArg.domain}`);
|
|
39
|
-
}
|
|
40
|
-
throw destroyError;
|
|
41
|
-
}
|
|
40
|
+
await this.destroyRuntime(previousRuntime);
|
|
42
41
|
}
|
|
42
|
+
const runtime = await this.createRuntime(integrationArg, configArg, contextArg);
|
|
43
43
|
this.activateRuntime(integrationArg.domain, runtime);
|
|
44
44
|
return runtime;
|
|
45
|
-
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
this.setupDomainsInProgress.delete(integrationArg.domain);
|
|
48
|
+
}
|
|
46
49
|
}
|
|
47
50
|
activateRuntime(domainArg, runtimeArg) {
|
|
48
51
|
if (runtimeArg.domain !== domainArg) {
|
|
@@ -64,16 +67,19 @@ export class IntegrationRuntimeManager {
|
|
|
64
67
|
retireRuntime(domainArg, expectedRuntimeArg) {
|
|
65
68
|
const runtime = this.removeRuntime(domainArg, expectedRuntimeArg);
|
|
66
69
|
if (runtime) {
|
|
67
|
-
this.
|
|
70
|
+
this.markRuntimePendingCleanup(domainArg, runtime);
|
|
68
71
|
}
|
|
69
72
|
return runtime;
|
|
70
73
|
}
|
|
71
74
|
destroyRuntime(runtimeArg, timeoutMsArg) {
|
|
72
75
|
this.retireRuntime(runtimeArg.domain, runtimeArg);
|
|
73
76
|
if (this.destroyedRuntimes.has(runtimeArg)) {
|
|
77
|
+
this.runtimesPendingCleanup.delete(runtimeArg);
|
|
74
78
|
return Promise.resolve();
|
|
75
79
|
}
|
|
76
|
-
this.runtimesPendingCleanup.
|
|
80
|
+
if (!this.runtimesPendingCleanup.has(runtimeArg)) {
|
|
81
|
+
this.markRuntimePendingCleanup(runtimeArg.domain, runtimeArg);
|
|
82
|
+
}
|
|
77
83
|
let destructionPromise = this.runtimeDestructionPromises.get(runtimeArg);
|
|
78
84
|
if (!destructionPromise) {
|
|
79
85
|
const destroyAttempt = Promise.resolve().then(() => runtimeArg.destroy());
|
|
@@ -103,6 +109,24 @@ export class IntegrationRuntimeManager {
|
|
|
103
109
|
listRuntimes() {
|
|
104
110
|
return [...this.runtimes.values()];
|
|
105
111
|
}
|
|
112
|
+
async retryPendingCleanup(domainArg) {
|
|
113
|
+
const runtimes = [...this.runtimesPendingCleanup]
|
|
114
|
+
.filter(([, cleanupDomainArg]) => cleanupDomainArg === domainArg)
|
|
115
|
+
.map(([runtimeArg]) => runtimeArg);
|
|
116
|
+
if (runtimes.length === 0) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const results = await Promise.allSettled(runtimes.map((runtimeArg) => this.destroyRuntime(runtimeArg)));
|
|
120
|
+
const errors = results
|
|
121
|
+
.filter((resultArg) => resultArg.status === 'rejected')
|
|
122
|
+
.map((resultArg) => resultArg.reason);
|
|
123
|
+
if (errors.length > 0) {
|
|
124
|
+
throw new AggregateError(errors, `Failed to clean up retained integration runtimes for ${domainArg}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
hasPendingCleanup(domainArg) {
|
|
128
|
+
return [...this.runtimesPendingCleanup.values()].some((cleanupDomainArg) => cleanupDomainArg === domainArg);
|
|
129
|
+
}
|
|
106
130
|
async writeDeviceFeature(requestArg, expectedRuntimeArg, abortSignalArg) {
|
|
107
131
|
const integrationDomain = requestArg.device.integrationDomain;
|
|
108
132
|
if (!integrationDomain) {
|
|
@@ -132,21 +156,20 @@ export class IntegrationRuntimeManager {
|
|
|
132
156
|
}
|
|
133
157
|
return runtime.writeFeature(requestArg, abortSignalArg);
|
|
134
158
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
.
|
|
145
|
-
.map((resultArg) => resultArg.reason);
|
|
146
|
-
if (errors.length > 0) {
|
|
147
|
-
throw new AggregateError(errors, 'Failed to destroy all integration runtimes cleanly');
|
|
159
|
+
destroyAll(timeoutMsArg) {
|
|
160
|
+
if (this.destroyAllPromise) {
|
|
161
|
+
return this.destroyAllPromise;
|
|
162
|
+
}
|
|
163
|
+
if (this.setupDomainsInProgress.size > 0) {
|
|
164
|
+
return Promise.reject(new Error('Cannot destroy integration runtimes while setup is in progress.'));
|
|
165
|
+
}
|
|
166
|
+
const destroyAllPromise = this.performDestroyAll(timeoutMsArg).finally(() => {
|
|
167
|
+
if (this.destroyAllPromise === destroyAllPromise) {
|
|
168
|
+
this.destroyAllPromise = undefined;
|
|
148
169
|
}
|
|
149
170
|
});
|
|
171
|
+
this.destroyAllPromise = destroyAllPromise;
|
|
172
|
+
return destroyAllPromise;
|
|
150
173
|
}
|
|
151
174
|
async withTimeout(promiseArg, timeoutMsArg, messageArg) {
|
|
152
175
|
let timeout;
|
|
@@ -162,12 +185,24 @@ export class IntegrationRuntimeManager {
|
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
}
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
.
|
|
168
|
-
.
|
|
169
|
-
|
|
170
|
-
|
|
188
|
+
async performDestroyAll(timeoutMsArg) {
|
|
189
|
+
for (const [domain, runtime] of this.runtimes) {
|
|
190
|
+
this.runtimes.delete(domain);
|
|
191
|
+
this.markRuntimePendingCleanup(domain, runtime);
|
|
192
|
+
}
|
|
193
|
+
const runtimes = [...this.runtimesPendingCleanup.keys()];
|
|
194
|
+
const results = await Promise.allSettled(runtimes.map((runtimeArg) => this.destroyRuntime(runtimeArg, timeoutMsArg)));
|
|
195
|
+
const errors = results
|
|
196
|
+
.filter((resultArg) => resultArg.status === 'rejected')
|
|
197
|
+
.map((resultArg) => resultArg.reason);
|
|
198
|
+
if (errors.length > 0) {
|
|
199
|
+
throw new AggregateError(errors, 'Failed to destroy all integration runtimes cleanly');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
markRuntimePendingCleanup(domainArg, runtimeArg) {
|
|
203
|
+
if (!this.runtimesPendingCleanup.has(runtimeArg)) {
|
|
204
|
+
this.runtimesPendingCleanup.set(runtimeArg, domainArg);
|
|
205
|
+
}
|
|
171
206
|
}
|
|
172
207
|
}
|
|
173
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5ydW50aW1lbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NvcmUvY2xhc3Nlcy5ydW50aW1lbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQVE5RixNQUFNLE9BQU8seUJBQXlCO0lBQ25CLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBK0IsQ0FBQztJQUNsRCxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBdUIsQ0FBQztJQUN4RCwwQkFBMEIsR0FBRyxJQUFJLEdBQUcsRUFBc0MsQ0FBQztJQUMzRSxpQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBdUIsQ0FBQztJQUNoRSxhQUFhLEdBQXFCLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztJQUVyRCxLQUFLLENBQUMsYUFBYSxDQUN4QixjQUF3QyxFQUN4QyxTQUFrQixFQUNsQixhQUF1QyxFQUFFO1FBRXpDLElBQUksY0FBYyxDQUFDLE1BQU0sS0FBSyxpQkFBaUIsRUFBRSxDQUFDO1lBQ2hELE1BQU0sb0NBQW9DLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxNQUFNLE9BQU8sR0FBRyxNQUFNLGNBQWMsQ0FBQyxLQUFLLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2xFLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDN0MsTUFBTSxXQUFXLEdBQUcsSUFBSSxLQUFLLENBQzNCLGlEQUFpRCxjQUFjLENBQUMsTUFBTSxjQUFjLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FDckcsQ0FBQztZQUNGLElBQUksQ0FBQztnQkFDSCxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDckMsQ0FBQztZQUFDLE9BQU8sWUFBWSxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSxjQUFjLENBQ3RCLENBQUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxFQUMzQixzREFBc0QsY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUM5RSxDQUFDO1lBQ0osQ0FBQztZQUNELE1BQU0sV0FBVyxDQUFDO1FBQ3BCLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRU0sS0FBSyxDQUFDLGdCQUFnQixDQUMzQixjQUF3QyxFQUN4QyxTQUFrQixFQUNsQixhQUF1QyxFQUFFO1FBRXpDLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLElBQUksRUFBRTtZQUNsQyxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsY0FBYyxFQUFFLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUNoRixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUVsRSxJQUFJLGVBQWUsRUFBRSxDQUFDO2dCQUNwQixJQUFJLENBQUM7b0JBQ0gsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUFDLGVBQWUsQ0FBQyxDQUFDO2dCQUM3QyxDQUFDO2dCQUFDLE9BQU8sWUFBWSxFQUFFLENBQUM7b0JBQ3RCLElBQUksQ0FBQzt3QkFDSCxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLENBQUM7b0JBQ3JDLENBQUM7b0JBQUMsT0FBTyxZQUFZLEVBQUUsQ0FBQzt3QkFDdEIsTUFBTSxJQUFJLGNBQWMsQ0FDdEIsQ0FBQyxZQUFZLEVBQUUsWUFBWSxDQUFDLEVBQzVCLDZDQUE2QyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQ3JFLENBQUM7b0JBQ0osQ0FBQztvQkFDRCxNQUFNLFlBQVksQ0FBQztnQkFDckIsQ0FBQztZQUNILENBQUM7WUFFRCxJQUFJLENBQUMsZUFBZSxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDckQsT0FBTyxPQUFPLENBQUM7UUFDakIsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sZUFBZSxDQUFDLFNBQWlCLEVBQUUsVUFBK0I7UUFDdkUsSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQ2IsaURBQWlELFNBQVMsY0FBYyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQzVGLENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckQsSUFBSSxDQUFDLHNCQUFzQixDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUMvQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDekMsT0FBTyxlQUFlLENBQUM7SUFDekIsQ0FBQztJQUVNLGFBQWEsQ0FBQyxTQUFpQixFQUFFLGtCQUF3QztRQUM5RSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsa0JBQWtCLElBQUksT0FBTyxLQUFLLGtCQUFrQixDQUFDLEVBQUUsQ0FBQztZQUN2RSxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEMsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVNLGFBQWEsQ0FBQyxTQUFpQixFQUFFLGtCQUF3QztRQUM5RSxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ2xFLElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLENBQUMsc0JBQXNCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzNDLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRU0sY0FBYyxDQUNuQixVQUErQixFQUMvQixZQUFxQjtRQUVyQixJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbEQsSUFBSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDM0MsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDNUMsSUFBSSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3pFLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sY0FBYyxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDMUUsa0JBQWtCLEdBQUcsY0FBYztpQkFDaEMsSUFBSSxDQUFDLEdBQUcsRUFBRTtnQkFDVCxJQUFJLENBQUMsaUJBQWlCLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN2QyxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2pELENBQUMsQ0FBQztpQkFDRCxPQUFPLENBQUMsR0FBRyxFQUFFO2dCQUNaLElBQUksSUFBSSxDQUFDLDBCQUEwQixDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsS0FBSyxrQkFBa0IsRUFBRSxDQUFDO29CQUMzRSxJQUFJLENBQUMsMEJBQTBCLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUNyRCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7WUFDTCxJQUFJLENBQUMsMEJBQTBCLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7UUFDRCxJQUFJLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUMvQixPQUFPLGtCQUFrQixDQUFDO1FBQzVCLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQ3JCLGtCQUFrQixFQUNsQixZQUFZLEVBQ1osNENBQTRDLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FDakUsQ0FBQztJQUNKLENBQUM7SUFFTSxnQkFBZ0IsQ0FBQyxTQUFpQjtRQUN2QyxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFFTSxVQUFVLENBQUMsU0FBaUI7UUFDakMsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVNLFlBQVk7UUFDakIsT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFTSxLQUFLLENBQUMsa0JBQWtCLENBQzdCLFVBQXNDLEVBQ3RDLGtCQUF3QyxFQUN4QyxjQUE0QjtRQUU1QixNQUFNLGlCQUFpQixHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLENBQUM7UUFDOUQsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDdkIsT0FBTztnQkFDTCxPQUFPLEVBQUUsS0FBSztnQkFDZCxLQUFLLEVBQUUsVUFBVSxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsNEJBQTRCO2FBQ2xFLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDYixPQUFPO2dCQUNMLE9BQU8sRUFBRSxLQUFLO2dCQUNkLEtBQUssRUFBRSxzQ0FBc0MsaUJBQWlCLEVBQUU7YUFDakUsQ0FBQztRQUNKLENBQUM7UUFDRCxJQUFJLGtCQUFrQixJQUFJLE9BQU8sS0FBSyxrQkFBa0IsRUFBRSxDQUFDO1lBQ3pELE9BQU87Z0JBQ0wsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsS0FBSyxFQUFFLDBDQUEwQyxpQkFBaUIsRUFBRTthQUNyRSxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDMUIsT0FBTztnQkFDTCxPQUFPLEVBQUUsS0FBSztnQkFDZCxLQUFLLEVBQUUsK0RBQStELGlCQUFpQixFQUFFO2FBQzFGLENBQUM7UUFDSixDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxjQUFjLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRU0sS0FBSyxDQUFDLFVBQVUsQ0FBQyxZQUFxQjtRQUMzQyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDbEMsS0FBSyxNQUFNLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxJQUFJLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDOUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzdCLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDM0MsQ0FBQztZQUVELE1BQU0sUUFBUSxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsc0JBQXNCLENBQUMsQ0FBQztZQUNsRCxNQUFNLE9BQU8sR0FBRyxNQUFNLE9BQU8sQ0FBQyxVQUFVLENBQ3RDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQzVFLENBQUM7WUFDRixNQUFNLE1BQU0sR0FBRyxPQUFPO2lCQUNuQixNQUFNLENBQUMsQ0FBQyxTQUFTLEVBQXNDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxLQUFLLFVBQVUsQ0FBQztpQkFDMUYsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDeEMsSUFBSSxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUN0QixNQUFNLElBQUksY0FBYyxDQUFDLE1BQU0sRUFBRSxvREFBb0QsQ0FBQyxDQUFDO1lBQ3pGLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxLQUFLLENBQUMsV0FBVyxDQUN2QixVQUE0QixFQUM1QixZQUFvQixFQUNwQixVQUFrQjtRQUVsQixJQUFJLE9BQWtELENBQUM7UUFDdkQsTUFBTSxjQUFjLEdBQUcsSUFBSSxPQUFPLENBQVEsQ0FBQyxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDN0QsT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1FBQ3ZGLENBQUMsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxVQUFVLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQztRQUMxRCxDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLE9BQU8sRUFBRSxDQUFDO2dCQUNaLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN4QixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFTyxZQUFZLENBQVUsWUFBb0M7UUFDaEUsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsYUFBYTthQUN4QyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDO2FBQ3RCLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUN0QixJQUFJLENBQUMsYUFBYSxHQUFHLGdCQUFnQixDQUFDO1FBQ3RDLE9BQU8sZ0JBQWdCLENBQUM7SUFDMUIsQ0FBQztDQUNGIn0=
|
|
208
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5ydW50aW1lbWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2NvcmUvY2xhc3Nlcy5ydW50aW1lbWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQVE5RixNQUFNLE9BQU8seUJBQXlCO0lBQ25CLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBK0IsQ0FBQztJQUNsRCxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBK0IsQ0FBQztJQUNoRSwwQkFBMEIsR0FBRyxJQUFJLEdBQUcsRUFBc0MsQ0FBQztJQUMzRSxpQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBdUIsQ0FBQztJQUN2RCxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBQ3BELGlCQUFpQixDQUFpQjtJQUVuQyxLQUFLLENBQUMsYUFBYSxDQUN4QixjQUF3QyxFQUN4QyxTQUFrQixFQUNsQixhQUF1QyxFQUFFO1FBRXpDLElBQUksY0FBYyxDQUFDLE1BQU0sS0FBSyxpQkFBaUIsRUFBRSxDQUFDO1lBQ2hELE1BQU0sb0NBQW9DLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxNQUFNLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDdEQsTUFBTSxPQUFPLEdBQUcsTUFBTSxjQUFjLENBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNsRSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzdDLE1BQU0sV0FBVyxHQUFHLElBQUksS0FBSyxDQUMzQixpREFBaUQsY0FBYyxDQUFDLE1BQU0sY0FBYyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQ3JHLENBQUM7WUFDRixJQUFJLENBQUMseUJBQXlCLENBQUMsY0FBYyxD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
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -65,7 +65,7 @@ const matches = await engine.validateCandidate({
|
|
|
65
65
|
console.log(matches);
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
The hub uses the same primitives through `discoverIntegrationCandidates()` and `setupIntegration(...)`, then reconciles each runtime's complete normalized device snapshot into the canonical registry. Devices absent from a later snapshot are removed.
|
|
68
|
+
The hub uses the same primitives through `discoverIntegrationCandidates()` and `setupIntegration(...)`, then reconciles each runtime's complete normalized device snapshot into the canonical registry. Devices absent from a later snapshot are removed. `IntegrationRuntimeManager.createRuntime()` and `setupIntegration()` retry retained cleanup for the requested domain before invoking integration setup and fail closed with an `AggregateError` while cleanup still fails. Replacement setup destroys the previous runtime before constructing its successor, and overlapping same-domain setup calls are rejected. Failed replacement and mismatched-runtime cleanup remains retained under the requested domain; `retryPendingCleanup(domain)` is the explicit no-timeout retry entry point, while `hasPendingCleanup(domain)` exposes whether that gate remains closed.
|
|
69
69
|
|
|
70
70
|
Runtime setup receives an optional abort signal. Device snapshots, subscriptions, and feature writes can also accept abort signals, allowing the hub to bound setup, synchronization, and writes. A control runtime may implement `writeFeature(...)`, `callService(...)`, or both; authoritative readable state still comes from a later `devices()` snapshot rather than an optimistic write. Every runtime implements `destroy()` for explicit cleanup.
|
|
71
71
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -9,10 +9,11 @@ import type {
|
|
|
9
9
|
|
|
10
10
|
export class IntegrationRuntimeManager {
|
|
11
11
|
private readonly runtimes = new Map<string, IIntegrationRuntime>();
|
|
12
|
-
private readonly runtimesPendingCleanup = new
|
|
12
|
+
private readonly runtimesPendingCleanup = new Map<IIntegrationRuntime, string>();
|
|
13
13
|
private readonly runtimeDestructionPromises = new Map<IIntegrationRuntime, Promise<void>>();
|
|
14
14
|
private readonly destroyedRuntimes = new WeakSet<IIntegrationRuntime>();
|
|
15
|
-
private
|
|
15
|
+
private readonly setupDomainsInProgress = new Set<string>();
|
|
16
|
+
private destroyAllPromise?: Promise<void>;
|
|
16
17
|
|
|
17
18
|
public async createRuntime<TConfig>(
|
|
18
19
|
integrationArg: BaseIntegration<TConfig>,
|
|
@@ -22,11 +23,13 @@ export class IntegrationRuntimeManager {
|
|
|
22
23
|
if (integrationArg.status === 'descriptor-only') {
|
|
23
24
|
throw createDescriptorOnlyIntegrationError(integrationArg.domain);
|
|
24
25
|
}
|
|
26
|
+
await this.retryPendingCleanup(integrationArg.domain);
|
|
25
27
|
const runtime = await integrationArg.setup(configArg, contextArg);
|
|
26
28
|
if (runtime.domain !== integrationArg.domain) {
|
|
27
29
|
const domainError = new Error(
|
|
28
30
|
`Integration runtime domain mismatch: expected ${integrationArg.domain}, received ${runtime.domain}`
|
|
29
31
|
);
|
|
32
|
+
this.markRuntimePendingCleanup(integrationArg.domain, runtime);
|
|
30
33
|
try {
|
|
31
34
|
await this.destroyRuntime(runtime);
|
|
32
35
|
} catch (destroyError) {
|
|
@@ -45,29 +48,25 @@ export class IntegrationRuntimeManager {
|
|
|
45
48
|
configArg: TConfig,
|
|
46
49
|
contextArg: IIntegrationSetupContext = {}
|
|
47
50
|
): Promise<IIntegrationRuntime> {
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
if (this.destroyAllPromise) {
|
|
52
|
+
throw new Error('Cannot set up an integration while destroyAll is in progress.');
|
|
53
|
+
}
|
|
54
|
+
if (this.setupDomainsInProgress.has(integrationArg.domain)) {
|
|
55
|
+
throw new Error(`Integration setup is already in progress: ${integrationArg.domain}`);
|
|
56
|
+
}
|
|
57
|
+
this.setupDomainsInProgress.add(integrationArg.domain);
|
|
58
|
+
try {
|
|
59
|
+
await this.retryPendingCleanup(integrationArg.domain);
|
|
50
60
|
const previousRuntime = this.retireRuntime(integrationArg.domain);
|
|
51
|
-
|
|
52
61
|
if (previousRuntime) {
|
|
53
|
-
|
|
54
|
-
await this.destroyRuntime(previousRuntime);
|
|
55
|
-
} catch (destroyError) {
|
|
56
|
-
try {
|
|
57
|
-
await this.destroyRuntime(runtime);
|
|
58
|
-
} catch (cleanupError) {
|
|
59
|
-
throw new AggregateError(
|
|
60
|
-
[destroyError, cleanupError],
|
|
61
|
-
`Failed to replace integration runtime for ${integrationArg.domain}`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
throw destroyError;
|
|
65
|
-
}
|
|
62
|
+
await this.destroyRuntime(previousRuntime);
|
|
66
63
|
}
|
|
67
|
-
|
|
64
|
+
const runtime = await this.createRuntime(integrationArg, configArg, contextArg);
|
|
68
65
|
this.activateRuntime(integrationArg.domain, runtime);
|
|
69
66
|
return runtime;
|
|
70
|
-
}
|
|
67
|
+
} finally {
|
|
68
|
+
this.setupDomainsInProgress.delete(integrationArg.domain);
|
|
69
|
+
}
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
public activateRuntime(domainArg: string, runtimeArg: IIntegrationRuntime): IIntegrationRuntime | undefined {
|
|
@@ -94,7 +93,7 @@ export class IntegrationRuntimeManager {
|
|
|
94
93
|
public retireRuntime(domainArg: string, expectedRuntimeArg?: IIntegrationRuntime): IIntegrationRuntime | undefined {
|
|
95
94
|
const runtime = this.removeRuntime(domainArg, expectedRuntimeArg);
|
|
96
95
|
if (runtime) {
|
|
97
|
-
this.
|
|
96
|
+
this.markRuntimePendingCleanup(domainArg, runtime);
|
|
98
97
|
}
|
|
99
98
|
return runtime;
|
|
100
99
|
}
|
|
@@ -105,9 +104,12 @@ export class IntegrationRuntimeManager {
|
|
|
105
104
|
): Promise<void> {
|
|
106
105
|
this.retireRuntime(runtimeArg.domain, runtimeArg);
|
|
107
106
|
if (this.destroyedRuntimes.has(runtimeArg)) {
|
|
107
|
+
this.runtimesPendingCleanup.delete(runtimeArg);
|
|
108
108
|
return Promise.resolve();
|
|
109
109
|
}
|
|
110
|
-
this.runtimesPendingCleanup.
|
|
110
|
+
if (!this.runtimesPendingCleanup.has(runtimeArg)) {
|
|
111
|
+
this.markRuntimePendingCleanup(runtimeArg.domain, runtimeArg);
|
|
112
|
+
}
|
|
111
113
|
let destructionPromise = this.runtimeDestructionPromises.get(runtimeArg);
|
|
112
114
|
if (!destructionPromise) {
|
|
113
115
|
const destroyAttempt = Promise.resolve().then(() => runtimeArg.destroy());
|
|
@@ -145,6 +147,33 @@ export class IntegrationRuntimeManager {
|
|
|
145
147
|
return [...this.runtimes.values()];
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
public async retryPendingCleanup(domainArg: string): Promise<void> {
|
|
151
|
+
const runtimes = [...this.runtimesPendingCleanup]
|
|
152
|
+
.filter(([, cleanupDomainArg]) => cleanupDomainArg === domainArg)
|
|
153
|
+
.map(([runtimeArg]) => runtimeArg);
|
|
154
|
+
if (runtimes.length === 0) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const results = await Promise.allSettled(
|
|
158
|
+
runtimes.map((runtimeArg) => this.destroyRuntime(runtimeArg))
|
|
159
|
+
);
|
|
160
|
+
const errors = results
|
|
161
|
+
.filter((resultArg): resultArg is PromiseRejectedResult => resultArg.status === 'rejected')
|
|
162
|
+
.map((resultArg) => resultArg.reason);
|
|
163
|
+
if (errors.length > 0) {
|
|
164
|
+
throw new AggregateError(
|
|
165
|
+
errors,
|
|
166
|
+
`Failed to clean up retained integration runtimes for ${domainArg}`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public hasPendingCleanup(domainArg: string): boolean {
|
|
172
|
+
return [...this.runtimesPendingCleanup.values()].some(
|
|
173
|
+
(cleanupDomainArg) => cleanupDomainArg === domainArg
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
148
177
|
public async writeDeviceFeature(
|
|
149
178
|
requestArg: IDeviceFeatureWriteRequest,
|
|
150
179
|
expectedRuntimeArg?: IIntegrationRuntime,
|
|
@@ -181,24 +210,20 @@ export class IntegrationRuntimeManager {
|
|
|
181
210
|
return runtime.writeFeature(requestArg, abortSignalArg);
|
|
182
211
|
}
|
|
183
212
|
|
|
184
|
-
public
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
);
|
|
195
|
-
const errors = results
|
|
196
|
-
.filter((resultArg): resultArg is PromiseRejectedResult => resultArg.status === 'rejected')
|
|
197
|
-
.map((resultArg) => resultArg.reason);
|
|
198
|
-
if (errors.length > 0) {
|
|
199
|
-
throw new AggregateError(errors, 'Failed to destroy all integration runtimes cleanly');
|
|
213
|
+
public destroyAll(timeoutMsArg?: number): Promise<void> {
|
|
214
|
+
if (this.destroyAllPromise) {
|
|
215
|
+
return this.destroyAllPromise;
|
|
216
|
+
}
|
|
217
|
+
if (this.setupDomainsInProgress.size > 0) {
|
|
218
|
+
return Promise.reject(new Error('Cannot destroy integration runtimes while setup is in progress.'));
|
|
219
|
+
}
|
|
220
|
+
const destroyAllPromise = this.performDestroyAll(timeoutMsArg).finally(() => {
|
|
221
|
+
if (this.destroyAllPromise === destroyAllPromise) {
|
|
222
|
+
this.destroyAllPromise = undefined;
|
|
200
223
|
}
|
|
201
224
|
});
|
|
225
|
+
this.destroyAllPromise = destroyAllPromise;
|
|
226
|
+
return destroyAllPromise;
|
|
202
227
|
}
|
|
203
228
|
|
|
204
229
|
private async withTimeout<TResult>(
|
|
@@ -219,11 +244,30 @@ export class IntegrationRuntimeManager {
|
|
|
219
244
|
}
|
|
220
245
|
}
|
|
221
246
|
|
|
222
|
-
private
|
|
223
|
-
const
|
|
224
|
-
.
|
|
225
|
-
.
|
|
226
|
-
|
|
227
|
-
|
|
247
|
+
private async performDestroyAll(timeoutMsArg?: number): Promise<void> {
|
|
248
|
+
for (const [domain, runtime] of this.runtimes) {
|
|
249
|
+
this.runtimes.delete(domain);
|
|
250
|
+
this.markRuntimePendingCleanup(domain, runtime);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const runtimes = [...this.runtimesPendingCleanup.keys()];
|
|
254
|
+
const results = await Promise.allSettled(
|
|
255
|
+
runtimes.map((runtimeArg) => this.destroyRuntime(runtimeArg, timeoutMsArg))
|
|
256
|
+
);
|
|
257
|
+
const errors = results
|
|
258
|
+
.filter((resultArg): resultArg is PromiseRejectedResult => resultArg.status === 'rejected')
|
|
259
|
+
.map((resultArg) => resultArg.reason);
|
|
260
|
+
if (errors.length > 0) {
|
|
261
|
+
throw new AggregateError(errors, 'Failed to destroy all integration runtimes cleanly');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
private markRuntimePendingCleanup(
|
|
266
|
+
domainArg: string,
|
|
267
|
+
runtimeArg: IIntegrationRuntime
|
|
268
|
+
): void {
|
|
269
|
+
if (!this.runtimesPendingCleanup.has(runtimeArg)) {
|
|
270
|
+
this.runtimesPendingCleanup.set(runtimeArg, domainArg);
|
|
271
|
+
}
|
|
228
272
|
}
|
|
229
273
|
}
|