@uns-kit/core 3.0.36 → 3.0.38
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/MIGRATIONS.md +76 -0
- package/README.md +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/application-handover-state.d.ts +13 -0
- package/dist/runtime/application-handover-state.d.ts.map +1 -0
- package/dist/runtime/application-handover-state.js +43 -0
- package/dist/runtime/application-handover-state.js.map +1 -0
- package/dist/runtime/input-queue-boundary.d.ts +15 -0
- package/dist/runtime/input-queue-boundary.d.ts.map +1 -0
- package/dist/runtime/input-queue-boundary.js +33 -0
- package/dist/runtime/input-queue-boundary.js.map +1 -0
- package/dist/runtime/mqtt-handover-state.d.ts +8 -1
- package/dist/runtime/mqtt-handover-state.d.ts.map +1 -1
- package/dist/runtime/mqtt-handover-state.js +11 -4
- package/dist/runtime/mqtt-handover-state.js.map +1 -1
- package/dist/runtime/process-work.d.ts +16 -0
- package/dist/runtime/process-work.d.ts.map +1 -0
- package/dist/runtime/process-work.js +34 -0
- package/dist/runtime/process-work.js.map +1 -0
- package/dist/uns/handover-manager.d.ts +8 -1
- package/dist/uns/handover-manager.d.ts.map +1 -1
- package/dist/uns/handover-manager.js +128 -24
- package/dist/uns/handover-manager.js.map +1 -1
- package/dist/uns/handover-shutdown.d.ts +2 -0
- package/dist/uns/handover-shutdown.d.ts.map +1 -1
- package/dist/uns/handover-shutdown.js +1 -1
- package/dist/uns/handover-shutdown.js.map +1 -1
- package/dist/uns/uns-interfaces.d.ts +6 -0
- package/dist/uns/uns-interfaces.d.ts.map +1 -1
- package/dist/uns/uns-interfaces.js.map +1 -1
- package/dist/uns/uns-proxy-process.d.ts +14 -0
- package/dist/uns/uns-proxy-process.d.ts.map +1 -1
- package/dist/uns/uns-proxy-process.js +94 -7
- package/dist/uns/uns-proxy-process.js.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.d.ts +1 -0
- package/dist/uns-mqtt/mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.js +1 -0
- package/dist/uns-mqtt/mqtt-proxy.js.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.js +11 -0
- package/dist/uns-mqtt/mqtt-worker.js.map +1 -1
- package/dist/uns-mqtt/subscription-readiness.d.ts +2 -0
- package/dist/uns-mqtt/subscription-readiness.d.ts.map +1 -1
- package/dist/uns-mqtt/subscription-readiness.js +5 -1
- package/dist/uns-mqtt/subscription-readiness.js.map +1 -1
- package/dist/uns-mqtt/throttled-queue.d.ts +5 -8
- package/dist/uns-mqtt/throttled-queue.d.ts.map +1 -1
- package/dist/uns-mqtt/throttled-queue.js +25 -1
- package/dist/uns-mqtt/throttled-queue.js.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +10 -8
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.js +43 -3
- package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cloneApplicationHandoverState } from "../runtime/application-handover-state.js";
|
|
1
2
|
import { mqttHandoverOfferSchema, parseMqttHandoverState, mqttHandoverStateDigest } from "../runtime/mqtt-handover-state.js";
|
|
2
3
|
import logger from "../logger.js";
|
|
3
4
|
import { runHandoverShutdown, validateHandoverShutdown } from "./handover-shutdown.js";
|
|
@@ -17,6 +18,7 @@ function normalizeHandoverId(value) {
|
|
|
17
18
|
*/
|
|
18
19
|
export class HandoverManager {
|
|
19
20
|
statefulHandover;
|
|
21
|
+
applicationState;
|
|
20
22
|
event = new HandoverManagerEventEmitter();
|
|
21
23
|
processName;
|
|
22
24
|
processId;
|
|
@@ -38,12 +40,16 @@ export class HandoverManager {
|
|
|
38
40
|
stateDigest;
|
|
39
41
|
acceptedStateDigest;
|
|
40
42
|
targetPreparation;
|
|
43
|
+
targetStateApplied = false;
|
|
41
44
|
finRetry;
|
|
45
|
+
requestRetry;
|
|
46
|
+
sourceReviewInFlight = false;
|
|
42
47
|
handoverRequestEnabled = false;
|
|
43
48
|
handoverEnabled = true;
|
|
44
49
|
forceStartEnabled = false;
|
|
45
|
-
constructor(processName, processId, mqttProxy, unsMqttProxies, handoverRequestEnabled, handoverEnabled, forceStartEnabled, handoverId, shutdownHooks, statefulHandover = false) {
|
|
50
|
+
constructor(processName, processId, mqttProxy, unsMqttProxies, handoverRequestEnabled, handoverEnabled, forceStartEnabled, handoverId, shutdownHooks, statefulHandover = false, applicationState) {
|
|
46
51
|
this.statefulHandover = statefulHandover;
|
|
52
|
+
this.applicationState = applicationState;
|
|
47
53
|
validateHandoverShutdown(shutdownHooks);
|
|
48
54
|
this.shutdownHooks = shutdownHooks ? { ...shutdownHooks } : undefined;
|
|
49
55
|
this.processName = processName;
|
|
@@ -59,17 +65,23 @@ export class HandoverManager {
|
|
|
59
65
|
const version = PACKAGE_INFO.version;
|
|
60
66
|
this.topicBuilder = new MqttTopicBuilder(`uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`);
|
|
61
67
|
// Set status as active after a timeout if no other active process are detected.
|
|
62
|
-
this.activeTimeout = setTimeout(() => {
|
|
68
|
+
this.activeTimeout = setTimeout(async () => {
|
|
63
69
|
if (this.statefulHandover && this.handoverId)
|
|
64
70
|
return; // A reviewed successor never self-promotes.
|
|
65
71
|
logger.info(`${this.processName} - No active message received within timeout. Assuming no other process is running.`);
|
|
72
|
+
for (const proxy of this.unsMqttProxies)
|
|
73
|
+
proxy.setPublisherActive();
|
|
74
|
+
try {
|
|
75
|
+
await this.activateApplication();
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
logger.error("Runtime activation failed; successor remains passive");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
66
81
|
this.active = true;
|
|
67
82
|
this.event.emit("handoverManager", { active: this.active });
|
|
68
|
-
//
|
|
69
|
-
this.unsMqttProxies.forEach((unsProxy) =>
|
|
70
|
-
unsProxy.setPublisherActive();
|
|
71
|
-
unsProxy.setSubscriberActive();
|
|
72
|
-
});
|
|
83
|
+
// Publishers were prepared for application activation; input opens last.
|
|
84
|
+
this.unsMqttProxies.forEach((unsProxy) => unsProxy.setSubscriberActive());
|
|
73
85
|
}, ACTIVE_TIMEOUT);
|
|
74
86
|
}
|
|
75
87
|
getUserProperties(handoverId) {
|
|
@@ -182,16 +194,35 @@ export class HandoverManager {
|
|
|
182
194
|
},
|
|
183
195
|
});
|
|
184
196
|
logger.info(`${this.processName} - Requesting handover in 10 seconds.`);
|
|
185
|
-
setTimeout(
|
|
186
|
-
logger.info(`${this.processName} - Requesting handover ${eventHandoverTopic}.`);
|
|
197
|
+
setTimeout(() => {
|
|
187
198
|
this.handoverInProgress = true;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
|
|
199
|
+
let retries = 0;
|
|
200
|
+
const request = async () => {
|
|
201
|
+
if (this.targetPreparation || this.acceptedStateDigest) {
|
|
202
|
+
clearInterval(this.requestRetry);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const offer = this.statefulHandover ? await Promise.all(this.unsMqttProxies.map(proxy => proxy.getHandoverOffer())) : undefined;
|
|
207
|
+
await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload("handover_request", undefined, this.statefulHandover ? { offer, applicationContract: this.applicationState?.contract } : {}), {
|
|
208
|
+
retain: false, properties: { responseTopic: this.topicBuilder.getHandoverTopic(), userProperties: this.getUserProperties() },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
logger.warn("MQTT input boundary preparation is not ready; successor remains passive");
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
void request();
|
|
216
|
+
if (this.statefulHandover) {
|
|
217
|
+
this.requestRetry = setInterval(() => {
|
|
218
|
+
if (++retries > 15 || this.targetPreparation || this.acceptedStateDigest) {
|
|
219
|
+
clearInterval(this.requestRetry);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
void request();
|
|
223
|
+
}, 1000);
|
|
224
|
+
this.requestRetry.unref();
|
|
225
|
+
}
|
|
195
226
|
}, 10000);
|
|
196
227
|
}
|
|
197
228
|
else {
|
|
@@ -201,13 +232,13 @@ export class HandoverManager {
|
|
|
201
232
|
logger.warn(`${this.processName} - Warning: Source and destination being the same may lead to duplicate messages.`);
|
|
202
233
|
clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.
|
|
203
234
|
this.activeTimeout = undefined;
|
|
235
|
+
for (const proxy of this.unsMqttProxies)
|
|
236
|
+
proxy.setPublisherActive();
|
|
237
|
+
await this.activateApplication();
|
|
204
238
|
this.active = true;
|
|
205
239
|
this.event.emit("handoverManager", { active: this.active });
|
|
206
240
|
// Activate all UNS proxy instance publishers and subscribers.
|
|
207
|
-
this.unsMqttProxies.forEach((unsProxy) =>
|
|
208
|
-
unsProxy.setPublisherActive();
|
|
209
|
-
unsProxy.setSubscriberActive();
|
|
210
|
-
});
|
|
241
|
+
this.unsMqttProxies.forEach((unsProxy) => unsProxy.setSubscriberActive());
|
|
211
242
|
}
|
|
212
243
|
else {
|
|
213
244
|
logger.info(`${this.processName} - Waiting for the other process on topic ${event.topic} to become passive.`);
|
|
@@ -252,7 +283,11 @@ export class HandoverManager {
|
|
|
252
283
|
await this.shutdownHooks?.drain();
|
|
253
284
|
for (const proxy of this.unsMqttProxies)
|
|
254
285
|
await proxy.flush();
|
|
255
|
-
|
|
286
|
+
const application = this.applicationState ? { contract: this.applicationState.contract,
|
|
287
|
+
data: cloneApplicationHandoverState(this.applicationState.exportState()) } : undefined;
|
|
288
|
+
if (application)
|
|
289
|
+
this.applicationState.validateState(application.data);
|
|
290
|
+
this.preparedState = parseMqttHandoverState({ protocol: 1, ...(application ? { application } : {}), proxies: this.unsMqttProxies.map((proxy, i) => proxy.exportHandoverState({ batchSize: mqttWorkerData[i].batchSize, referenceHash: mqttWorkerData[i].referenceHash, ...(mqttWorkerData[i].processedTail ? { processedTail: mqttWorkerData[i].processedTail } : {}) })) });
|
|
256
291
|
this.stateDigest = mqttHandoverStateDigest(this.preparedState);
|
|
257
292
|
await this.sendPreparedState(event, handoverId);
|
|
258
293
|
let retries = 0;
|
|
@@ -308,6 +343,10 @@ export class HandoverManager {
|
|
|
308
343
|
const digest = mqttHandoverStateDigest(state);
|
|
309
344
|
if (digest !== response.stateDigest)
|
|
310
345
|
throw Error("MQTT handover state digest mismatch");
|
|
346
|
+
if (state.application?.contract !== this.applicationState?.contract)
|
|
347
|
+
throw Error("Application handover contract differs");
|
|
348
|
+
if (state.application)
|
|
349
|
+
this.applicationState.validateState(state.application.data);
|
|
311
350
|
const byName = new Map(this.unsMqttProxies.map(proxy => [proxy.instanceName, proxy]));
|
|
312
351
|
if (byName.size !== this.unsMqttProxies.length || state.proxies.length !== byName.size || state.proxies.some(p => !byName.has(p.instanceName)))
|
|
313
352
|
throw Error("MQTT handover proxy set differs");
|
|
@@ -316,16 +355,50 @@ export class HandoverManager {
|
|
|
316
355
|
// Validate every cursor before importing any state or activating any subscriber.
|
|
317
356
|
for (const snapshot of state.proxies)
|
|
318
357
|
await byName.get(snapshot.instanceName).prepareHandoverResume(snapshot.cursor);
|
|
358
|
+
// After this point an import/activation error has an unknown effect. Only
|
|
359
|
+
// read-only boundary preparation may be retried on a repeated FIN.
|
|
360
|
+
this.targetStateApplied = true;
|
|
319
361
|
for (const snapshot of state.proxies)
|
|
320
362
|
byName.get(snapshot.instanceName).importHandoverState(snapshot);
|
|
363
|
+
if (state.application)
|
|
364
|
+
await this.applicationState.importState(state.application.data);
|
|
321
365
|
for (const proxy of this.unsMqttProxies)
|
|
322
366
|
proxy.setPublisherActive();
|
|
323
|
-
|
|
324
|
-
|
|
367
|
+
await this.activateApplication();
|
|
368
|
+
try {
|
|
369
|
+
for (const proxy of this.unsMqttProxies)
|
|
370
|
+
await proxy.activateHandoverResume();
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
await this.deactivateApplication();
|
|
374
|
+
throw Error("MQTT input activation failed; successor remains passive");
|
|
375
|
+
}
|
|
325
376
|
this.acceptedStateDigest = digest;
|
|
326
377
|
this.active = true;
|
|
327
378
|
this.event.emit("handoverManager", { active: true });
|
|
328
379
|
}
|
|
380
|
+
async activateApplication() {
|
|
381
|
+
try {
|
|
382
|
+
await this.shutdownHooks?.onActivate?.();
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
await this.deactivateApplication();
|
|
386
|
+
throw Error("Application activation failed; successor remains passive");
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
async deactivateApplication() {
|
|
390
|
+
this.active = false;
|
|
391
|
+
try {
|
|
392
|
+
this.shutdownHooks?.onRelease?.();
|
|
393
|
+
}
|
|
394
|
+
catch { /* Keep admission closed if cleanup itself fails. */ }
|
|
395
|
+
// A failed worker may not acknowledge the stop. Request passive input on
|
|
396
|
+
// every peer, close outputs, and never acknowledge ownership as successful.
|
|
397
|
+
for (const proxy of this.unsMqttProxies) {
|
|
398
|
+
void Promise.resolve().then(() => proxy.setSubscriberPassive(true)).catch(() => { });
|
|
399
|
+
}
|
|
400
|
+
await Promise.allSettled(this.unsMqttProxies.map(proxy => Promise.resolve().then(() => proxy.setPublisherPassive())));
|
|
401
|
+
}
|
|
329
402
|
async finishSourceHandover() {
|
|
330
403
|
const result = await runHandoverShutdown(async () => {
|
|
331
404
|
await this.sourcePreparation;
|
|
@@ -376,10 +449,33 @@ export class HandoverManager {
|
|
|
376
449
|
return;
|
|
377
450
|
if (this.statefulHandover) {
|
|
378
451
|
// Reject incompatible upgrades before freezing the current owner.
|
|
452
|
+
if (response.applicationContract !== this.applicationState?.contract)
|
|
453
|
+
throw Error("Application handover contract differs; source remains active");
|
|
454
|
+
if (this.applicationState) {
|
|
455
|
+
const preliminary = cloneApplicationHandoverState(this.applicationState.exportState());
|
|
456
|
+
this.applicationState.validateState(preliminary);
|
|
457
|
+
}
|
|
379
458
|
const offer = mqttHandoverOfferSchema.parse(response.offer);
|
|
380
459
|
const own = this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility());
|
|
381
460
|
if (offer.length !== own.length || own.some(p => !offer.some(o => o.instanceName === p.instanceName && o.compatibility === p.compatibility)))
|
|
382
461
|
throw Error("MQTT source/destination or semantic contract differs; source remains active");
|
|
462
|
+
if (this.sourceReviewInFlight)
|
|
463
|
+
return;
|
|
464
|
+
this.sourceReviewInFlight = true;
|
|
465
|
+
try {
|
|
466
|
+
// Hints only: actual frozen cursors are revalidated by every target
|
|
467
|
+
// worker before activation. A quiet/unready source keeps admission.
|
|
468
|
+
for (const proxy of this.unsMqttProxies) {
|
|
469
|
+
const preview = offer.find(candidate => candidate.instanceName === proxy.instanceName).inputPreview;
|
|
470
|
+
if (!await proxy.canPrepareHandoverInput(preview))
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
finally {
|
|
475
|
+
this.sourceReviewInFlight = false;
|
|
476
|
+
}
|
|
477
|
+
if (this.sourcePeerId || !this.active)
|
|
478
|
+
return;
|
|
383
479
|
}
|
|
384
480
|
this.sourcePeerId = peerId;
|
|
385
481
|
this.acceptedHandoverId = this.getHandoverId(response, event);
|
|
@@ -423,7 +519,15 @@ export class HandoverManager {
|
|
|
423
519
|
return;
|
|
424
520
|
if (this.acceptedStateDigest && response.stateDigest !== this.acceptedStateDigest)
|
|
425
521
|
return;
|
|
426
|
-
this.
|
|
522
|
+
clearInterval(this.requestRetry);
|
|
523
|
+
if (!this.targetPreparation) {
|
|
524
|
+
const preparation = this.acceptPreparedState(response);
|
|
525
|
+
this.targetPreparation = preparation;
|
|
526
|
+
void preparation.catch(() => {
|
|
527
|
+
if (!this.targetStateApplied && this.targetPreparation === preparation)
|
|
528
|
+
this.targetPreparation = undefined;
|
|
529
|
+
});
|
|
530
|
+
}
|
|
427
531
|
await this.targetPreparation;
|
|
428
532
|
// Duplicate fin only replays the receipt; it never reapplies a baseline.
|
|
429
533
|
if (response.stateDigest !== this.acceptedStateDigest)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handover-manager.js","sourceRoot":"","sources":["../../src/uns/handover-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,uBAAuB,EAA0B,MAAM,mCAAmC,CAAC;AACrJ,OAAO,MAAM,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAA8B,MAAM,wBAAwB,CAAC;AAGnH,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAErE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnE,SAAS,mBAAmB,CAAC,KAAc;IACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAChC,OAAO,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AACpF,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAqCP;IApCZ,KAAK,GAAuD,IAAI,2BAA2B,EAAyB,CAAC;IACpH,WAAW,CAAS;IACpB,SAAS,CAAS;IAClB,SAAS,CAAY;IACrB,cAAc,CAAiB;IAC/B,kBAAkB,GAAY,KAAK,CAAC;IACpC,kBAAkB,GAAY,KAAK,CAAC;IACpC,YAAY,CAAmB;IAC/B,aAAa,CAA6B;IACjC,UAAU,CAAqB;IACxC,kBAAkB,CAAqB;IACvC,MAAM,GAAY,KAAK,CAAC;IACxB,YAAY,CAAqB;IACjC,iBAAiB,CAA4B;IAC7C,UAAU,CAA4B;IAC7B,aAAa,CAAoC;IAC1D,gBAAgB,CAAqB;IACrC,aAAa,CAAgC;IAC7C,WAAW,CAAqB;IAChC,mBAAmB,CAAqB;IACxC,iBAAiB,CAA4B;IAC7C,QAAQ,CAA6B;IACtC,sBAAsB,GAAY,KAAK,CAAC;IACxC,eAAe,GAAY,IAAI,CAAC;IAChC,iBAAiB,GAAY,KAAK,CAAC;IAE1C,YACE,WAAmB,EACnB,SAAiB,EACjB,SAAoB,EACpB,cAA8B,EAC9B,sBAA+B,EAC/B,eAAwB,EACxB,iBAA0B,EAC1B,UAAmB,EACnB,aAAqC,EACpB,mBAAmB,KAAK;QAAxB,qBAAgB,GAAhB,gBAAgB,CAAQ;QAEzC,wBAAwB,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACtE,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QACrC,IAAI,CAAC,sBAAsB,GAAG,sBAAsB,CAAC;QACrD,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;QAElD,iCAAiC;QACjC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC;QACtC,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,IAAI,gBAAgB,CACtC,aAAa,gBAAgB,CAAC,iBAAiB,CAAC,WAAW,CAAC,IAAI,gBAAgB,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CACvK,CAAC;QAEF,gFAAgF;QAChF,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YACnC,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,UAAU;gBAAE,OAAO,CAAC,4CAA4C;YAClG,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,qFAAqF,CAAC,CAAC;YACtH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAC5D,8DAA8D;YAC9D,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;gBACvC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;gBAC9B,QAAQ,CAAC,mBAAmB,EAAE,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC,EAAE,cAAc,CAAC,CAAC;IACrB,CAAC;IAEO,iBAAiB,CAAC,UAAmB;QAC3C,MAAM,UAAU,GAA2B;YACzC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;QACF,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QACtE,IAAI,UAAU;YAAE,UAAU,CAAC,UAAU,GAAG,UAAU,CAAC;QACnD,OAAO,UAAU,CAAC;IACpB,CAAC;IAEO,eAAe,CACrB,IAAY,EACZ,UAAmB,EACnB,SAAkC,EAAE;QAEpC,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,IAAI;YACJ,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjD,GAAG,MAAM;YACT,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClD,CAAC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,QAAiB,EAAE,KAAyB;QAChE,MAAM,WAAW,GAAG,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YACtF,CAAC,CAAE,QAAqC,CAAC,UAAU;YACnD,CAAC,CAAC,SAAS,CAAC;QACd,IAAI,OAAO,WAAW,KAAK,QAAQ;YAAE,OAAO,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC7E,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,CAAC;QAC5E,OAAO,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,CAAC;IAEO,uBAAuB,CAAC,kBAAsC;QACpE,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,KAAK,kBAAkB,EAAE,CAAC;YAC3C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,qDAAqD,CAAC,CAAC;QACtF,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,kBAAkB,CAAC,KAAyB;QAClD,OAAO,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,CAAC;IAC7D,CAAC;IAEO,gBAAgB,CAAC,OAAe;QACtC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;YAClE,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gBACvE,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;gBACzE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAa;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,AAAD,EAAG,OAAO,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QAC3C,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5D,MAAM,eAAe,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC9E,MAAM,eAAe,GAAG,gBAAgB,CAAC,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7E,OAAO,GAAG,KAAK,eAAe,IAAI,OAAO,KAAK,eAAe,CAAC;IAChE,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,iBAAiB,CAAC,KAAyB;QACtD,IAAI,CAAC;YACH,8FAA8F;YAC9F,IAAI,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,kBAAkB,KAAK,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,CAAC,kBAAkB,KAAK,KAAK,EAAE,CAAC;gBAC9I,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBACvD,IAAI,eAAe,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;oBACvC,OAAO;gBACT,CAAC;gBACD,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACpE,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;oBACzB,OAAO;gBACT,CAAC;gBACD,MAAM,UAAU,GAAG,eAAe,CAAC,CAAC,CAAC,eAAe,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,+BAA+B,UAAU,OAAO,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;gBAE/F,IAAI,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;oBAClC,uEAAuE;oBACvE,sEAAsE;oBACtE,qEAAqE;oBACrE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,uEAAuE,CAAC,CAAC;oBACxG,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAC;oBAC9B,OAAO;gBACT,CAAC;gBAED,IAAI,IAAI,CAAC,sBAAsB,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;oBACxD,oBAAoB;oBACpB,6EAA6E;oBAC7E,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,qGAAqG;oBACvI,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;oBAC/B,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;oBAC5D,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;oBAC/B,IAAI,CAAC,gBAAgB,GAAG,eAAe,CAAC;oBACxC,MAAM,kBAAkB,GAAG,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC;oBACnH,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC,EAAE;wBACxF,MAAM,EAAE,KAAK;wBACb,UAAU,EAAE;4BACV,cAAc,EAAE,IAAI,CAAC,iBAAiB,EAAE;yBACzC;qBACF,CAAC,CAAC;oBACH,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,uCAAuC,CAAC,CAAC;oBACxE,UAAU,CAAC,KAAK,IAAI,EAAE;wBACpB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,0BAA0B,kBAAkB,GAAG,CAAC,CAAC;wBAChF,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;wBAC/B,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,eAAe,CAAC,kBAAkB,EAAE,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE;4BAChN,MAAM,EAAE,KAAK;4BACb,UAAU,EAAE;gCACV,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;gCACnD,cAAc,EAAE,IAAI,CAAC,iBAAiB,EAAE;6BACzC;yBACF,CAAC,CAAC;oBACL,CAAC,EAAE,KAAK,CAAC,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;wBAC3B,6DAA6D;wBAC7D,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,gCAAgC,CAAC,CAAC;wBACjE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,mFAAmF,CAAC,CAAC;wBACpH,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,qGAAqG;wBACvI,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;wBAC/B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;wBACnB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;wBAC5D,8DAA8D;wBAC9D,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;4BACvC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;4BAC9B,QAAQ,CAAC,mBAAmB,EAAE,CAAC;wBACjC,CAAC,CAAC,CAAC;oBACL,CAAC;yBAAM,CAAC;wBACN,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,6CAA6C,KAAK,CAAC,KAAK,qBAAqB,CAAC,CAAC;wBAC9G,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAC;oBAChC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,wEAAwE;YACxE,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBACjF,MAAM,eAAe,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBACvD,IAAI,eAAe,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;oBACvC,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,qCAAqC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;IACH,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,IAAY;QAC7B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,qBAAqB,CAAC,QAAa,EAAE,KAAyB;QAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAEvD,MAAM,CAAC,IAAI,CACT,GAAG,IAAI,CAAC,WAAW,qCAAqC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,uBAAuB,CACrI,CAAC;QAEF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,aAAa,EAAE,SAAS,EAAE,EAAE,CAAC;QAElC,yEAAyE;QACzE,MAAM,cAAc,GAA8B,EAAE,CAAC;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,iCAAiC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAC3F,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YAC1B,sFAAsF;YACtF,MAAM,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;YAClC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc;gBAAE,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7D,IAAI,CAAC,aAAa,GAAG,sBAAsB,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CACvG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5H,IAAI,CAAC,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC/D,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;YAChD,IAAI,OAAO,GAAG,CAAC,CAAC;YAChB,IAAI,CAAC,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;gBAC/B,IAAI,EAAE,OAAO,GAAG,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oBAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;oBAAC,OAAO;gBAAC,CAAC;gBAChF,KAAK,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC,CAAC;YACrH,CAAC,EAAE,IAAI,CAAC,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtB,gFAAgF;YAChF,OAAO;QACT,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,qEAAqE,CAAC,CAAC;QAEtG,uFAAuF;QACvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,UAAU,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,UAAU,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAC1B,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,EAC5C,IAAI,CAAC,eAAe,CAAC,qBAAqB,EAAE,UAAU,EAAE;oBACtD,SAAS,EAAE,UAAU,CAAC,SAAS;oBAC/B,aAAa,EAAE,UAAU,CAAC,aAAa;oBACvC,YAAY,EAAE,UAAU,CAAC,YAAY;iBACtC,CAAC,EACF;oBACE,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE;wBACV,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;wBACnD,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;qBACnD;iBACF,CACF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,uCAAuC,CAAC,CAAC;QAExE,yDAAyD;QACzD,8CAA8C;QAC9C,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAC1B,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,EAC5C,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,UAAU,CAAC,EAChD;YACE,MAAM,EAAE,KAAK;YACb,UAAU,EAAE;gBACV,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;gBACnD,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;aACnD;SACF,CACF,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,+BAA+B,CAAC,CAAC;QAEhE,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,QAAsB,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1F,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,KAAyB,EAAE,UAAmB;QAC5E,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,UAAU,EACxH,EAAE,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,EAAE;YAC7D,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE;SAC/I,CAAC,CAAC;IACP,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,QAAa;QAC7C,MAAM,KAAK,GAAG,sBAAsB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,MAAM,KAAK,QAAQ,CAAC,WAAW;YAAE,MAAM,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACxF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACtF,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,cAAc,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YAC5I,MAAM,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QACzG,iFAAiF;QACjF,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACtH,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAE,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QACvG,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc;YAAE,KAAK,CAAC,kBAAkB,EAAE,CAAC;QACpE,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,cAAc;YAAE,MAAM,KAAK,CAAC,sBAAsB,EAAE,CAAC;QAC9E,IAAI,CAAC,mBAAmB,GAAG,MAAM,CAAC;QAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAEO,KAAK,CAAC,oBAAoB;QAChC,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,KAAK,IAAI,EAAE;YAClD,MAAM,IAAI,CAAC,iBAAiB,CAAC;YAC7B,MAAM,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;YAClC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAC1B,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAClE,uEAAuE;gBACvE,sEAAsE;gBACrE,OAAuE,CAAC,IAAI,CAAC,+BAA+B,EAAE;oBAC7G,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,kBAAkB;oBAChD,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,CAAC;oBAChD,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM;iBACpC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,IAAI,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;QAChC,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC;QAChC,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,sDAAsD,CAAC,CAAC;YACvF,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,kFAAkF;YAClF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,4BAA4B,MAAM,kCAAkC,CAAC,CAAC;YACtG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,KAAyB;QACpD,IAAI,CAAC;YACH,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO;gBAAE,OAAO;YAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YACtD,gFAAgF;YAChF,IAAI,CAAC,QAAQ,CAAC,QAAQ,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,gBAAgB;gBAAE,OAAO;YAChE,IAAI,IAAI,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAAE,OAAO;YACpG,oBAAoB;YACpB,+FAA+F;YAC/F,IAAI,QAAQ,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;gBACzC,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBAC9C,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,CAAC;gBAC3D,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM,IAAI,IAAI,CAAC,kBAAkB,KAAK,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnJ,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;oBAAC,OAAO;gBACvE,CAAC;gBACD,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,UAAU;oBAAE,OAAO;gBAC1G,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC1B,kEAAkE;oBAClE,MAAM,KAAK,GAAG,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,wBAAwB,EAAE,CAAC,CAAC;oBAC/E,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa,CAAC,CAAC;wBAC1I,MAAM,KAAK,CAAC,6EAA6E,CAAC,CAAC;gBAC/F,CAAC;gBACD,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;gBAC3B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC9D,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;gBAC/B,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;gBACjC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBAC/B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACrE,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,iBAAiB,CAAC;gBAC/B,CAAC;gBAAC,MAAM,CAAC;oBACP,sFAAsF;oBACtF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,mEAAmE,CAAC,CAAC;oBACrG,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,gBAAgB;wBAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBACrE,CAAC;YACH,CAAC;YAED,oBAAoB;YACpB,iGAAiG;YACjG,qCAAqC;YACrC,IAAI,QAAQ,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC5C,IAAI,IAAI,CAAC,gBAAgB;oBAAE,OAAO;gBAClC,IAAI,IAAI,CAAC,YAAY;oBAAE,OAAO;gBAC9B,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAAE,OAAO;gBAC/E,2EAA2E;gBAC3E,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAsB,EAAE,EAAE;oBACrD,IAAI,QAAQ,CAAC,YAAY,KAAK,QAAQ,CAAC,YAAY,EAAE,CAAC;wBACpD,QAAQ,CAAC,mBAAmB,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;oBAC3E,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,oBAAoB;YACpB,oFAAoF;YACpF,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAC/C,IAAI,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,kBAAkB,IAAI,EAAE,KAAK,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,gBAAgB;wBAAE,OAAO;oBAChJ,IAAI,IAAI,CAAC,mBAAmB,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC,mBAAmB;wBAAE,OAAO;oBAC1F,IAAI,CAAC,iBAAiB,KAAK,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;oBAC9D,MAAM,IAAI,CAAC,iBAAiB,CAAC;oBAC7B,yEAAyE;oBACzE,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC,mBAAmB;wBAAE,OAAO;oBAC9D,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,EAAE,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,EAAE,EAChH,EAAE,WAAW,EAAE,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;oBACrI,OAAO;gBACT,CAAC;gBACD,IAAI,IAAI,CAAC,YAAY;oBAAE,OAAO;gBAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACvD,IAAI,CAAC,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC;oBAAE,OAAO;gBACtD,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,iCAAiC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,GAAG,CAAC,CAAC;gBAE1H,2EAA2E;gBAC3E,mCAAmC;gBACnC,mCAAmC;gBAEnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACnB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC5D,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,wBAAwB,CAAC,CAAC;gBACzD,8DAA8D;gBAC9D,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACvC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;oBAC9B,QAAQ,CAAC,mBAAmB,EAAE,CAAC;gBACjC,CAAC,CAAC,CAAC;gBAEH,2CAA2C;gBAC3C,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAC1B,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,IAAI,EAAE,EAC5C,IAAI,CAAC,eAAe,CAAC,cAAc,EAAE,UAAU,CAAC,EAChD;oBACE,MAAM,EAAE,KAAK;oBACb,UAAU,EAAE;wBACV,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE;wBACnD,cAAc,EAAE,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;qBACnD;iBACF,CACF,CAAC;gBACF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,+BAA+B,CAAC,CAAC;YAClE,CAAC;YAED,oBAAoB;YACpB,6EAA6E;YAC7E,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,YAAY;oBAAE,OAAO;gBAC5F,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACvD,IAAI,IAAI,CAAC,kBAAkB,IAAI,UAAU,IAAI,IAAI,CAAC,kBAAkB,KAAK,UAAU,EAAE,CAAC;oBACpF,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,oDAAoD,CAAC,CAAC;oBACrF,OAAO;gBACT,CAAC;gBACD,IAAI,IAAI,CAAC,gBAAgB,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,kBAAkB,IAAI,QAAQ,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;oBAAE,OAAO;gBAChJ,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,iCAAiC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,GAAG,CAAC,CAAC;gBAC1H,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,oBAAoB,EAAE,CAAC;gBAChD,MAAM,IAAI,CAAC,UAAU,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,WAAW,0CAA0C,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7F,CAAC;IACH,CAAC;CACF","sourcesContent":["import { mqttHandoverOfferSchema, parseMqttHandoverState, mqttHandoverStateDigest, type MqttHandoverState } from \"../runtime/mqtt-handover-state.js\";\nimport logger from \"../logger.js\";\nimport { runHandoverShutdown, validateHandoverShutdown, type HandoverShutdownHooks } from \"./handover-shutdown.js\";\nimport { HandoverManagerEvents } from \"../uns-mqtt/mqtt-interfaces.js\";\nimport MqttProxy from \"../uns-mqtt/mqtt-proxy.js\";\nimport { MqttTopicBuilder } from \"../uns-mqtt/mqtt-topic-builder.js\";\nimport UnsMqttProxy from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport { HandoverManagerEventEmitter } from \"./handover-manager-event-emitter.js\";\nimport { ACTIVE_TIMEOUT, PACKAGE_INFO } from \"./process-config.js\";\nimport { UnsEvents } from \"./uns-interfaces.js\";\n\nfunction normalizeHandoverId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= 128 ? normalized : undefined;\n}\n\n/**\n * HandoverManager is responsible for all handover-related logic,\n * including handling incoming MQTT messages, issuing handover requests,\n * and processing handover responses.\n */\nexport class HandoverManager {\n public event: HandoverManagerEventEmitter<HandoverManagerEvents> = new HandoverManagerEventEmitter<HandoverManagerEvents>();\n private processName: string;\n private processId: string;\n private mqttProxy: MqttProxy;\n private unsMqttProxies: UnsMqttProxy[];\n private requestingHandover: boolean = false;\n private handoverInProgress: boolean = false;\n private topicBuilder: MqttTopicBuilder;\n private activeTimeout: NodeJS.Timeout | undefined;\n private readonly handoverId: string | undefined;\n private acceptedHandoverId: string | undefined;\n private active: boolean = false;\n private sourcePeerId: string | undefined;\n private sourcePreparation: Promise<void> | undefined;\n private sourceExit: Promise<void> | undefined;\n private readonly shutdownHooks: HandoverShutdownHooks | undefined;\n private expectedSourceId: string | undefined;\n private preparedState: MqttHandoverState | undefined;\n private stateDigest: string | undefined;\n private acceptedStateDigest: string | undefined;\n private targetPreparation: Promise<void> | undefined;\n private finRetry: NodeJS.Timeout | undefined;\n public handoverRequestEnabled: boolean = false;\n public handoverEnabled: boolean = true;\n public forceStartEnabled: boolean = false;\n\n constructor(\n processName: string,\n processId: string,\n mqttProxy: MqttProxy,\n unsMqttProxies: UnsMqttProxy[],\n handoverRequestEnabled: boolean,\n handoverEnabled: boolean,\n forceStartEnabled: boolean,\n handoverId?: string,\n shutdownHooks?: HandoverShutdownHooks,\n private readonly statefulHandover = false,\n ) {\n validateHandoverShutdown(shutdownHooks);\n this.shutdownHooks = shutdownHooks ? { ...shutdownHooks } : undefined;\n this.processName = processName;\n this.processId = processId;\n this.mqttProxy = mqttProxy;\n this.unsMqttProxies = unsMqttProxies;\n this.handoverRequestEnabled = handoverRequestEnabled;\n this.handoverEnabled = handoverEnabled;\n this.forceStartEnabled = forceStartEnabled;\n this.handoverId = normalizeHandoverId(handoverId);\n\n // Instantiate the topic builder.\n const packageName = PACKAGE_INFO.name;\n const version = PACKAGE_INFO.version;\n this.topicBuilder = new MqttTopicBuilder(\n `uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`,\n );\n\n // Set status as active after a timeout if no other active process are detected.\n this.activeTimeout = setTimeout(() => {\n if (this.statefulHandover && this.handoverId) return; // A reviewed successor never self-promotes.\n logger.info(`${this.processName} - No active message received within timeout. Assuming no other process is running.`);\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n // Activate all UNS proxy instance publishers and subscribers.\n this.unsMqttProxies.forEach((unsProxy) => {\n unsProxy.setPublisherActive();\n unsProxy.setSubscriberActive();\n });\n }, ACTIVE_TIMEOUT);\n }\n\n private getUserProperties(handoverId?: string): Record<string, string> {\n const properties: Record<string, string> = {\n processName: this.processName,\n processId: this.processId,\n };\n const normalized = normalizeHandoverId(handoverId ?? this.handoverId);\n if (normalized) properties.handoverId = normalized;\n return properties;\n }\n\n private handoverPayload(\n type: string,\n handoverId?: string,\n fields: Record<string, unknown> = {},\n ): string {\n const normalized = normalizeHandoverId(handoverId ?? this.handoverId);\n return JSON.stringify({\n type,\n ...(this.statefulHandover ? { protocol: 2 } : {}),\n ...fields,\n ...(normalized ? { handoverId: normalized } : {}),\n });\n }\n\n private getHandoverId(response: unknown, event: UnsEvents[\"input\"]): string | undefined {\n const fromPayload = response && typeof response === \"object\" && !Array.isArray(response)\n ? (response as { handoverId?: unknown }).handoverId\n : undefined;\n if (typeof fromPayload === \"string\") return normalizeHandoverId(fromPayload);\n const fromProperties = event.packet?.properties?.userProperties?.handoverId;\n return typeof fromProperties === \"string\" ? normalizeHandoverId(fromProperties) : undefined;\n }\n\n private acceptsHandoverResponse(receivedHandoverId: string | undefined): boolean {\n if (!this.handoverId || !receivedHandoverId) {\n return true;\n }\n if (this.handoverId === receivedHandoverId) {\n return true;\n }\n logger.warn(`${this.processName} - Ignoring handover message for another migration.`);\n return false;\n }\n\n private getSourceProcessId(event: UnsEvents[\"input\"]): string | undefined {\n return event.packet?.properties?.userProperties?.processId;\n }\n\n private parseActiveValue(message: string): boolean | null {\n try {\n const parsed = JSON.parse(message);\n const value = parsed?.message?.data?.value ?? parsed?.data?.value;\n if (value === 1 || value === \"1\" || value === true || value === \"true\") {\n return true;\n }\n if (value === 0 || value === \"0\" || value === false || value === \"false\") {\n return false;\n }\n return null;\n } catch {\n return null;\n }\n }\n\n private isProcessActiveTopic(topic: string): boolean {\n const parts = topic.split(\"/\");\n if (parts.length !== 5) return false;\n const [root, pkg, , process, tail] = parts;\n if (root !== \"uns-infra\" || tail !== \"active\") return false;\n const expectedPackage = MqttTopicBuilder.sanitizeTopicPart(PACKAGE_INFO.name);\n const expectedProcess = MqttTopicBuilder.sanitizeTopicPart(this.processName);\n return pkg === expectedPackage && process === expectedProcess;\n }\n\n /**\n * Main entry point for handling incoming MQTT messages.\n * It checks the topic and delegates to the corresponding handler.\n */\n public async handleMqttMessage(event: UnsEvents[\"input\"]): Promise<void> {\n try {\n // Check if the packet is active messages from other processes and this process is not active.\n if (this.isProcessActiveTopic(event.topic) && this.requestingHandover === false && this.active === false && this.handoverInProgress === false) {\n const sourceProcessId = this.getSourceProcessId(event);\n if (sourceProcessId === this.processId) {\n return;\n }\n const activeValue = this.parseActiveValue(event.message.toString());\n if (activeValue !== true) {\n return;\n }\n const sourceInfo = sourceProcessId ? ` (processId=${sourceProcessId})` : \"\";\n logger.info(`${this.processName} - Another process is active${sourceInfo} on ${event.topic}.`);\n\n if (event.packet?.retain === true) {\n // A retained heartbeat can belong to a process that crashed before its\n // expiry. Wait for a fresh non-retained heartbeat before asking it to\n // hand over; otherwise a stale retained message would block startup.\n logger.info(`${this.processName} - Retained active heartbeat observed; waiting for a fresh heartbeat.`);\n this.activeTimeout?.refresh();\n return;\n }\n\n if (this.handoverRequestEnabled && this.handoverEnabled) {\n // Requester process\n // Publish a handover request message after 10 seconds to the handover topic.\n clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.\n this.activeTimeout = undefined;\n this.event.emit(\"handoverManager\", { active: this.active });\n this.requestingHandover = true;\n this.expectedSourceId = sourceProcessId;\n const eventHandoverTopic = new MqttTopicBuilder(MqttTopicBuilder.extractBaseTopic(event.topic)).getHandoverTopic();\n await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload(\"handover_intent\"), {\n retain: false,\n properties: {\n userProperties: this.getUserProperties(),\n },\n });\n logger.info(`${this.processName} - Requesting handover in 10 seconds.`);\n setTimeout(async () => {\n logger.info(`${this.processName} - Requesting handover ${eventHandoverTopic}.`);\n this.handoverInProgress = true;\n await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload(\"handover_request\", undefined, this.statefulHandover ? { offer: this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility()) } : {}), {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(),\n },\n });\n }, 10000);\n } else {\n if (this.forceStartEnabled) {\n // Force start the process even if another process is active.\n logger.info(`${this.processName} - Force starting the process.`);\n logger.warn(`${this.processName} - Warning: Source and destination being the same may lead to duplicate messages.`);\n clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.\n this.activeTimeout = undefined;\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n // Activate all UNS proxy instance publishers and subscribers.\n this.unsMqttProxies.forEach((unsProxy) => {\n unsProxy.setPublisherActive();\n unsProxy.setSubscriberActive();\n });\n } else {\n logger.info(`${this.processName} - Waiting for the other process on topic ${event.topic} to become passive.`);\n this.activeTimeout?.refresh();\n }\n }\n }\n\n // Check if the packet is an handover message, sent to a handover topic.\n if (event.topic === this.topicBuilder.getHandoverTopic() && this.handoverEnabled) {\n const sourceProcessId = this.getSourceProcessId(event);\n if (sourceProcessId !== this.processId) {\n await this.handleHandover(event);\n }\n }\n } catch (error) {\n logger.error(`${this.processName} - Error processing MQTT message: ${error.message}`);\n return;\n }\n }\n\n /**\n * Handles handovers.\n */\n private exitSource(code: number): void {\n process.exit(code);\n }\n\n private async prepareSourceHandover(response: any, event: UnsEvents[\"input\"]): Promise<void> {\n const handoverId = this.getHandoverId(response, event);\n\n logger.info(\n `${this.processName} - Received handover request from ${event.packet?.properties?.userProperties?.processName}. Accepting handover.`,\n );\n\n this.active = false;\n this.event.emit(\"handoverManager\", { active: false });\n this.shutdownHooks?.onRelease?.();\n\n // Set all UNS proxy instance subscribers to passive and drain the queue.\n const mqttWorkerData: UnsEvents[\"mqttWorker\"][] = [];\n for (let i = 0; i < this.unsMqttProxies.length; i++) {\n const unsProxy = this.unsMqttProxies[i];\n const workerData = await unsProxy.setSubscriberPassiveAndDrainQueue(this.statefulHandover);\n mqttWorkerData.push(workerData);\n }\n if (this.statefulHandover) {\n // Finish accepted application callbacks before taking the calculation-state boundary.\n await this.shutdownHooks?.drain();\n for (const proxy of this.unsMqttProxies) await proxy.flush();\n this.preparedState = parseMqttHandoverState({ protocol: 1, proxies: this.unsMqttProxies.map((proxy, i) =>\n proxy.exportHandoverState({ batchSize: mqttWorkerData[i].batchSize, referenceHash: mqttWorkerData[i].referenceHash })) });\n this.stateDigest = mqttHandoverStateDigest(this.preparedState);\n await this.sendPreparedState(event, handoverId);\n let retries = 0;\n this.finRetry = setInterval(() => {\n if (++retries > 30 || this.sourceExit) { clearInterval(this.finRetry); return; }\n void this.sendPreparedState(event, handoverId).catch(() => logger.warn(\"MQTT handover receipt retry unavailable\"));\n }, 1000);\n this.finRetry.unref();\n // Keep the old owner passive until the successor acknowledges this exact state.\n return;\n }\n logger.info(`${this.processName} - Handover request accepted. Sending handover_subscriber messages.`);\n\n // Publish handover_subscriber messages for each instance that has processed some data.\n for (let i = 0; i < mqttWorkerData.length; i++) {\n const workerData = mqttWorkerData[i];\n if (workerData.batchSize > 0) {\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_subscriber\", handoverId, {\n batchSize: workerData.batchSize,\n referenceHash: workerData.referenceHash,\n instanceName: workerData.instanceName,\n }),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n }\n }\n logger.info(`${this.processName} - Handover subscriber messages sent.`);\n\n // Publish a single handover acknowledgment only when all\n // handover_subscriber messages have been sent\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_fin\", handoverId),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n logger.info(`${this.processName} - Handover fin message sent.`);\n\n await Promise.all(this.unsMqttProxies.map((unsProxy: UnsMqttProxy) => unsProxy.stop()));\n }\n\n private async sendPreparedState(event: UnsEvents[\"input\"], handoverId?: string): Promise<void> {\n await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? \"\", this.handoverPayload(\"handover_fin\", handoverId,\n { state: this.preparedState, stateDigest: this.stateDigest }), {\n retain: false, qos: 1, properties: { responseTopic: this.topicBuilder.getHandoverTopic(), userProperties: this.getUserProperties(handoverId) },\n });\n }\n\n private async acceptPreparedState(response: any): Promise<void> {\n const state = parseMqttHandoverState(response.state);\n const digest = mqttHandoverStateDigest(state);\n if (digest !== response.stateDigest) throw Error(\"MQTT handover state digest mismatch\");\n const byName = new Map(this.unsMqttProxies.map(proxy => [proxy.instanceName, proxy]));\n if (byName.size !== this.unsMqttProxies.length || state.proxies.length !== byName.size || state.proxies.some(p => !byName.has(p.instanceName)))\n throw Error(\"MQTT handover proxy set differs\");\n for (const snapshot of state.proxies) byName.get(snapshot.instanceName)!.validateHandoverState(snapshot);\n // Validate every cursor before importing any state or activating any subscriber.\n for (const snapshot of state.proxies) await byName.get(snapshot.instanceName)!.prepareHandoverResume(snapshot.cursor);\n for (const snapshot of state.proxies) byName.get(snapshot.instanceName)!.importHandoverState(snapshot);\n for (const proxy of this.unsMqttProxies) proxy.setPublisherActive();\n for (const proxy of this.unsMqttProxies) await proxy.activateHandoverResume();\n this.acceptedStateDigest = digest;\n this.active = true;\n this.event.emit(\"handoverManager\", { active: true });\n }\n\n private async finishSourceHandover(): Promise<void> {\n const result = await runHandoverShutdown(async () => {\n await this.sourcePreparation;\n await this.shutdownHooks?.drain();\n if (this.statefulHandover) {\n await Promise.all(this.unsMqttProxies.map(proxy => proxy.stop()));\n // The host persists this receipt synchronously before the real process\n // exit. No receipt is emitted for a partial/failed application drain.\n (process as unknown as { emit(event: string, value: unknown): boolean }).emit(\"uns-kit:mqtt-handover-drained\", {\n protocol: 2, handoverId: this.acceptedHandoverId,\n stateDigest: this.stateDigest, pendingRecords: 0,\n outputs: this.unsMqttProxies.length,\n });\n }\n }, this.shutdownHooks?.timeoutMs ?? 30_000);\n this.handoverInProgress = false;\n this.requestingHandover = false;\n if (result === \"completed\") {\n logger.info(`${this.processName} - Handover source drain completed. Exiting process.`);\n this.exitSource(0);\n } else {\n // Do not log application error text: it may contain paths, topics or credentials.\n logger.error(`${this.processName} - Handover source drain ${result}. Exiting with incomplete drain.`);\n this.exitSource(1);\n }\n }\n\n private async handleHandover(event: UnsEvents[\"input\"]): Promise<void> {\n try {\n if (event.message.length > 1100000) return;\n const response = JSON.parse(event.message.toString());\n // No downgrade: stateful peers must agree before either relinquishes ownership.\n if ((response.protocol === 2) !== this.statefulHandover) return;\n if (this.statefulHandover && (event.packet?.retain || !this.getHandoverId(response, event))) return;\n // Responder process\n // Check if the message is a handover request and publish MULTIPLE handover_subscriber messages\n if (response.type === \"handover_request\") {\n const peerId = this.getSourceProcessId(event);\n const replyTopic = event.packet?.properties?.responseTopic;\n if (this.statefulHandover && this.sourcePeerId === peerId && this.acceptedHandoverId === this.getHandoverId(response, event) && this.preparedState) {\n await this.sendPreparedState(event, this.acceptedHandoverId); return;\n }\n if (this.sourcePeerId || !this.active || !peerId || typeof replyTopic !== \"string\" || !replyTopic) return;\n if (this.statefulHandover) {\n // Reject incompatible upgrades before freezing the current owner.\n const offer = mqttHandoverOfferSchema.parse(response.offer);\n const own = this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility());\n if (offer.length !== own.length || own.some(p => !offer.some(o => o.instanceName === p.instanceName && o.compatibility === p.compatibility)))\n throw Error(\"MQTT source/destination or semantic contract differs; source remains active\");\n }\n this.sourcePeerId = peerId;\n this.acceptedHandoverId = this.getHandoverId(response, event);\n this.handoverInProgress = true;\n clearTimeout(this.activeTimeout);\n this.activeTimeout = undefined;\n this.sourcePreparation = this.prepareSourceHandover(response, event);\n try {\n await this.sourcePreparation;\n } catch {\n // Subscriber transfer or onRelease failed; never report successful source completion.\n logger.error(`${this.processName} - Handover source preparation failed; ownership requires review.`);\n if (!this.sourceExit && !this.statefulHandover) this.exitSource(1);\n }\n }\n\n // Requestor process\n // Check if the message is one of the handover_subscriber message in response to handover_request\n // and publish a handover_ack message\n if (response.type === \"handover_subscriber\") {\n if (this.statefulHandover) return;\n if (this.sourcePeerId) return;\n if (!this.acceptsHandoverResponse(this.getHandoverId(response, event))) return;\n // Find correct unsProxy instance for handover_subscriber and set it active\n this.unsMqttProxies.forEach((unsProxy: UnsMqttProxy) => {\n if (unsProxy.instanceName === response.instanceName) {\n unsProxy.setSubscriberActive(response.batchSize, response.referenceHash);\n }\n });\n }\n\n // Requestor process\n // Check if the message is a handover_fin at the end of handover_subscriber messages\n if (response.type === \"handover_fin\") {\n if (this.statefulHandover) {\n const id = this.getHandoverId(response, event);\n if (this.sourcePeerId || !this.requestingHandover || id !== this.handoverId || this.getSourceProcessId(event) !== this.expectedSourceId) return;\n if (this.acceptedStateDigest && response.stateDigest !== this.acceptedStateDigest) return;\n this.targetPreparation ??= this.acceptPreparedState(response);\n await this.targetPreparation;\n // Duplicate fin only replays the receipt; it never reapplies a baseline.\n if (response.stateDigest !== this.acceptedStateDigest) return;\n await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? \"\", this.handoverPayload(\"handover_ack\", id,\n { stateDigest: this.acceptedStateDigest }), { retain: false, qos: 1, properties: { userProperties: this.getUserProperties(id) } });\n return;\n }\n if (this.sourcePeerId) return;\n const handoverId = this.getHandoverId(response, event);\n if (!this.acceptsHandoverResponse(handoverId)) return;\n logger.info(`${this.processName} - Received handover fin from ${event.packet?.properties?.userProperties?.processName}.`);\n\n // Maybe we should count the number of requests that were allrady made TODO\n // this.handoverInProgress = false;\n // this.requestingHandover = false;\n\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n logger.info(`${this.processName} - Handover completed.`);\n // Activate all UNS proxy instance publishers and subscribers.\n this.unsMqttProxies.forEach((unsProxy) => {\n unsProxy.setPublisherActive();\n unsProxy.setSubscriberActive();\n });\n\n // Maybe we should reply with handover_ack.\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_ack\", handoverId),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n logger.info(`${this.processName} - Handover ack message sent.`);\n }\n\n // Responder process\n // Check if the message is a handover_ack at the end of handover_fin messages\n if (response.type === \"handover_ack\") {\n if (!this.sourcePreparation || this.getSourceProcessId(event) !== this.sourcePeerId) return;\n const handoverId = this.getHandoverId(response, event);\n if (this.acceptedHandoverId && handoverId && this.acceptedHandoverId !== handoverId) {\n logger.warn(`${this.processName} - Ignoring acknowledgement for another migration.`);\n return;\n }\n if (this.statefulHandover && (handoverId !== this.acceptedHandoverId || response.stateDigest !== this.stateDigest || !this.stateDigest)) return;\n clearInterval(this.finRetry);\n logger.info(`${this.processName} - Received handover ack from ${event.packet?.properties?.userProperties?.processName}.`);\n this.sourceExit ??= this.finishSourceHandover();\n await this.sourceExit;\n }\n } catch (error) {\n logger.error(`${this.processName} - Error processing handover response: ${error.message}`);\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"handover-manager.js","sourceRoot":"","sources":["../../src/uns/handover-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { cloneApplicationHandoverState, type ApplicationHandoverState } from \"../runtime/application-handover-state.js\";\nimport { mqttHandoverOfferSchema, parseMqttHandoverState, mqttHandoverStateDigest, type MqttHandoverState } from \"../runtime/mqtt-handover-state.js\";\nimport logger from \"../logger.js\";\nimport { runHandoverShutdown, validateHandoverShutdown, type HandoverShutdownHooks } from \"./handover-shutdown.js\";\nimport { HandoverManagerEvents } from \"../uns-mqtt/mqtt-interfaces.js\";\nimport MqttProxy from \"../uns-mqtt/mqtt-proxy.js\";\nimport { MqttTopicBuilder } from \"../uns-mqtt/mqtt-topic-builder.js\";\nimport UnsMqttProxy from \"../uns-mqtt/uns-mqtt-proxy.js\";\nimport { HandoverManagerEventEmitter } from \"./handover-manager-event-emitter.js\";\nimport { ACTIVE_TIMEOUT, PACKAGE_INFO } from \"./process-config.js\";\nimport { UnsEvents } from \"./uns-interfaces.js\";\n\nfunction normalizeHandoverId(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= 128 ? normalized : undefined;\n}\n\n/**\n * HandoverManager is responsible for all handover-related logic,\n * including handling incoming MQTT messages, issuing handover requests,\n * and processing handover responses.\n */\nexport class HandoverManager {\n public event: HandoverManagerEventEmitter<HandoverManagerEvents> = new HandoverManagerEventEmitter<HandoverManagerEvents>();\n private processName: string;\n private processId: string;\n private mqttProxy: MqttProxy;\n private unsMqttProxies: UnsMqttProxy[];\n private requestingHandover: boolean = false;\n private handoverInProgress: boolean = false;\n private topicBuilder: MqttTopicBuilder;\n private activeTimeout: NodeJS.Timeout | undefined;\n private readonly handoverId: string | undefined;\n private acceptedHandoverId: string | undefined;\n private active: boolean = false;\n private sourcePeerId: string | undefined;\n private sourcePreparation: Promise<void> | undefined;\n private sourceExit: Promise<void> | undefined;\n private readonly shutdownHooks: HandoverShutdownHooks | undefined;\n private expectedSourceId: string | undefined;\n private preparedState: MqttHandoverState | undefined;\n private stateDigest: string | undefined;\n private acceptedStateDigest: string | undefined;\n private targetPreparation: Promise<void> | undefined;\n private targetStateApplied = false;\n private finRetry: NodeJS.Timeout | undefined;\n private requestRetry: NodeJS.Timeout | undefined;\n private sourceReviewInFlight = false;\n public handoverRequestEnabled: boolean = false;\n public handoverEnabled: boolean = true;\n public forceStartEnabled: boolean = false;\n\n constructor(\n processName: string,\n processId: string,\n mqttProxy: MqttProxy,\n unsMqttProxies: UnsMqttProxy[],\n handoverRequestEnabled: boolean,\n handoverEnabled: boolean,\n forceStartEnabled: boolean,\n handoverId?: string,\n shutdownHooks?: HandoverShutdownHooks,\n private readonly statefulHandover = false,\n private readonly applicationState?: ApplicationHandoverState,\n ) {\n validateHandoverShutdown(shutdownHooks);\n this.shutdownHooks = shutdownHooks ? { ...shutdownHooks } : undefined;\n this.processName = processName;\n this.processId = processId;\n this.mqttProxy = mqttProxy;\n this.unsMqttProxies = unsMqttProxies;\n this.handoverRequestEnabled = handoverRequestEnabled;\n this.handoverEnabled = handoverEnabled;\n this.forceStartEnabled = forceStartEnabled;\n this.handoverId = normalizeHandoverId(handoverId);\n\n // Instantiate the topic builder.\n const packageName = PACKAGE_INFO.name;\n const version = PACKAGE_INFO.version;\n this.topicBuilder = new MqttTopicBuilder(\n `uns-infra/${MqttTopicBuilder.sanitizeTopicPart(packageName)}/${MqttTopicBuilder.sanitizeTopicPart(version)}/${MqttTopicBuilder.sanitizeTopicPart(this.processName)}/`,\n );\n\n // Set status as active after a timeout if no other active process are detected.\n this.activeTimeout = setTimeout(async () => {\n if (this.statefulHandover && this.handoverId) return; // A reviewed successor never self-promotes.\n logger.info(`${this.processName} - No active message received within timeout. Assuming no other process is running.`);\n for (const proxy of this.unsMqttProxies) proxy.setPublisherActive();\n try { await this.activateApplication(); }\n catch { logger.error(\"Runtime activation failed; successor remains passive\"); return; }\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n // Publishers were prepared for application activation; input opens last.\n this.unsMqttProxies.forEach((unsProxy) => unsProxy.setSubscriberActive());\n }, ACTIVE_TIMEOUT);\n }\n\n private getUserProperties(handoverId?: string): Record<string, string> {\n const properties: Record<string, string> = {\n processName: this.processName,\n processId: this.processId,\n };\n const normalized = normalizeHandoverId(handoverId ?? this.handoverId);\n if (normalized) properties.handoverId = normalized;\n return properties;\n }\n\n private handoverPayload(\n type: string,\n handoverId?: string,\n fields: Record<string, unknown> = {},\n ): string {\n const normalized = normalizeHandoverId(handoverId ?? this.handoverId);\n return JSON.stringify({\n type,\n ...(this.statefulHandover ? { protocol: 2 } : {}),\n ...fields,\n ...(normalized ? { handoverId: normalized } : {}),\n });\n }\n\n private getHandoverId(response: unknown, event: UnsEvents[\"input\"]): string | undefined {\n const fromPayload = response && typeof response === \"object\" && !Array.isArray(response)\n ? (response as { handoverId?: unknown }).handoverId\n : undefined;\n if (typeof fromPayload === \"string\") return normalizeHandoverId(fromPayload);\n const fromProperties = event.packet?.properties?.userProperties?.handoverId;\n return typeof fromProperties === \"string\" ? normalizeHandoverId(fromProperties) : undefined;\n }\n\n private acceptsHandoverResponse(receivedHandoverId: string | undefined): boolean {\n if (!this.handoverId || !receivedHandoverId) {\n return true;\n }\n if (this.handoverId === receivedHandoverId) {\n return true;\n }\n logger.warn(`${this.processName} - Ignoring handover message for another migration.`);\n return false;\n }\n\n private getSourceProcessId(event: UnsEvents[\"input\"]): string | undefined {\n return event.packet?.properties?.userProperties?.processId;\n }\n\n private parseActiveValue(message: string): boolean | null {\n try {\n const parsed = JSON.parse(message);\n const value = parsed?.message?.data?.value ?? parsed?.data?.value;\n if (value === 1 || value === \"1\" || value === true || value === \"true\") {\n return true;\n }\n if (value === 0 || value === \"0\" || value === false || value === \"false\") {\n return false;\n }\n return null;\n } catch {\n return null;\n }\n }\n\n private isProcessActiveTopic(topic: string): boolean {\n const parts = topic.split(\"/\");\n if (parts.length !== 5) return false;\n const [root, pkg, , process, tail] = parts;\n if (root !== \"uns-infra\" || tail !== \"active\") return false;\n const expectedPackage = MqttTopicBuilder.sanitizeTopicPart(PACKAGE_INFO.name);\n const expectedProcess = MqttTopicBuilder.sanitizeTopicPart(this.processName);\n return pkg === expectedPackage && process === expectedProcess;\n }\n\n /**\n * Main entry point for handling incoming MQTT messages.\n * It checks the topic and delegates to the corresponding handler.\n */\n public async handleMqttMessage(event: UnsEvents[\"input\"]): Promise<void> {\n try {\n // Check if the packet is active messages from other processes and this process is not active.\n if (this.isProcessActiveTopic(event.topic) && this.requestingHandover === false && this.active === false && this.handoverInProgress === false) {\n const sourceProcessId = this.getSourceProcessId(event);\n if (sourceProcessId === this.processId) {\n return;\n }\n const activeValue = this.parseActiveValue(event.message.toString());\n if (activeValue !== true) {\n return;\n }\n const sourceInfo = sourceProcessId ? ` (processId=${sourceProcessId})` : \"\";\n logger.info(`${this.processName} - Another process is active${sourceInfo} on ${event.topic}.`);\n\n if (event.packet?.retain === true) {\n // A retained heartbeat can belong to a process that crashed before its\n // expiry. Wait for a fresh non-retained heartbeat before asking it to\n // hand over; otherwise a stale retained message would block startup.\n logger.info(`${this.processName} - Retained active heartbeat observed; waiting for a fresh heartbeat.`);\n this.activeTimeout?.refresh();\n return;\n }\n\n if (this.handoverRequestEnabled && this.handoverEnabled) {\n // Requester process\n // Publish a handover request message after 10 seconds to the handover topic.\n clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.\n this.activeTimeout = undefined;\n this.event.emit(\"handoverManager\", { active: this.active });\n this.requestingHandover = true;\n this.expectedSourceId = sourceProcessId;\n const eventHandoverTopic = new MqttTopicBuilder(MqttTopicBuilder.extractBaseTopic(event.topic)).getHandoverTopic();\n await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload(\"handover_intent\"), {\n retain: false,\n properties: {\n userProperties: this.getUserProperties(),\n },\n });\n logger.info(`${this.processName} - Requesting handover in 10 seconds.`);\n setTimeout(() => {\n this.handoverInProgress = true;\n let retries = 0;\n const request = async () => {\n if (this.targetPreparation || this.acceptedStateDigest) { clearInterval(this.requestRetry); return; }\n try {\n const offer = this.statefulHandover ? await Promise.all(this.unsMqttProxies.map(proxy => proxy.getHandoverOffer())) : undefined;\n await this.mqttProxy.publish(eventHandoverTopic, this.handoverPayload(\"handover_request\", undefined,\n this.statefulHandover ? { offer, applicationContract: this.applicationState?.contract } : {}), {\n retain: false, properties: { responseTopic: this.topicBuilder.getHandoverTopic(), userProperties: this.getUserProperties() },\n });\n } catch { logger.warn(\"MQTT input boundary preparation is not ready; successor remains passive\"); }\n };\n void request();\n if (this.statefulHandover) {\n this.requestRetry = setInterval(() => {\n if (++retries > 15 || this.targetPreparation || this.acceptedStateDigest) { clearInterval(this.requestRetry); return; }\n void request();\n }, 1000);\n this.requestRetry.unref();\n }\n }, 10000);\n } else {\n if (this.forceStartEnabled) {\n // Force start the process even if another process is active.\n logger.info(`${this.processName} - Force starting the process.`);\n logger.warn(`${this.processName} - Warning: Source and destination being the same may lead to duplicate messages.`);\n clearTimeout(this.activeTimeout); // Clear the active timeout if it exists - prevent this process from becoming active after a timeout.\n this.activeTimeout = undefined;\n for (const proxy of this.unsMqttProxies) proxy.setPublisherActive();\n await this.activateApplication();\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n // Activate all UNS proxy instance publishers and subscribers.\n this.unsMqttProxies.forEach((unsProxy) => unsProxy.setSubscriberActive());\n } else {\n logger.info(`${this.processName} - Waiting for the other process on topic ${event.topic} to become passive.`);\n this.activeTimeout?.refresh();\n }\n }\n }\n\n // Check if the packet is an handover message, sent to a handover topic.\n if (event.topic === this.topicBuilder.getHandoverTopic() && this.handoverEnabled) {\n const sourceProcessId = this.getSourceProcessId(event);\n if (sourceProcessId !== this.processId) {\n await this.handleHandover(event);\n }\n }\n } catch (error) {\n logger.error(`${this.processName} - Error processing MQTT message: ${error.message}`);\n return;\n }\n }\n\n /**\n * Handles handovers.\n */\n private exitSource(code: number): void {\n process.exit(code);\n }\n\n private async prepareSourceHandover(response: any, event: UnsEvents[\"input\"]): Promise<void> {\n const handoverId = this.getHandoverId(response, event);\n\n logger.info(\n `${this.processName} - Received handover request from ${event.packet?.properties?.userProperties?.processName}. Accepting handover.`,\n );\n\n this.active = false;\n this.event.emit(\"handoverManager\", { active: false });\n this.shutdownHooks?.onRelease?.();\n\n // Set all UNS proxy instance subscribers to passive and drain the queue.\n const mqttWorkerData: UnsEvents[\"mqttWorker\"][] = [];\n for (let i = 0; i < this.unsMqttProxies.length; i++) {\n const unsProxy = this.unsMqttProxies[i];\n const workerData = await unsProxy.setSubscriberPassiveAndDrainQueue(this.statefulHandover);\n mqttWorkerData.push(workerData);\n }\n if (this.statefulHandover) {\n // Finish accepted application callbacks before taking the calculation-state boundary.\n await this.shutdownHooks?.drain();\n for (const proxy of this.unsMqttProxies) await proxy.flush();\n const application = this.applicationState ? { contract: this.applicationState.contract,\n data: cloneApplicationHandoverState(this.applicationState.exportState()) } : undefined;\n if (application) this.applicationState!.validateState(application.data);\n this.preparedState = parseMqttHandoverState({ protocol: 1, ...(application ? { application } : {}), proxies: this.unsMqttProxies.map((proxy, i) =>\n proxy.exportHandoverState({ batchSize: mqttWorkerData[i].batchSize, referenceHash: mqttWorkerData[i].referenceHash, ...(mqttWorkerData[i].processedTail ? {processedTail: mqttWorkerData[i].processedTail} : {}) })) });\n this.stateDigest = mqttHandoverStateDigest(this.preparedState);\n await this.sendPreparedState(event, handoverId);\n let retries = 0;\n this.finRetry = setInterval(() => {\n if (++retries > 30 || this.sourceExit) { clearInterval(this.finRetry); return; }\n void this.sendPreparedState(event, handoverId).catch(() => logger.warn(\"MQTT handover receipt retry unavailable\"));\n }, 1000);\n this.finRetry.unref();\n // Keep the old owner passive until the successor acknowledges this exact state.\n return;\n }\n logger.info(`${this.processName} - Handover request accepted. Sending handover_subscriber messages.`);\n\n // Publish handover_subscriber messages for each instance that has processed some data.\n for (let i = 0; i < mqttWorkerData.length; i++) {\n const workerData = mqttWorkerData[i];\n if (workerData.batchSize > 0) {\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_subscriber\", handoverId, {\n batchSize: workerData.batchSize,\n referenceHash: workerData.referenceHash,\n instanceName: workerData.instanceName,\n }),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n }\n }\n logger.info(`${this.processName} - Handover subscriber messages sent.`);\n\n // Publish a single handover acknowledgment only when all\n // handover_subscriber messages have been sent\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_fin\", handoverId),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n logger.info(`${this.processName} - Handover fin message sent.`);\n\n await Promise.all(this.unsMqttProxies.map((unsProxy: UnsMqttProxy) => unsProxy.stop()));\n }\n\n private async sendPreparedState(event: UnsEvents[\"input\"], handoverId?: string): Promise<void> {\n await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? \"\", this.handoverPayload(\"handover_fin\", handoverId,\n { state: this.preparedState, stateDigest: this.stateDigest }), {\n retain: false, qos: 1, properties: { responseTopic: this.topicBuilder.getHandoverTopic(), userProperties: this.getUserProperties(handoverId) },\n });\n }\n\n private async acceptPreparedState(response: any): Promise<void> {\n const state = parseMqttHandoverState(response.state);\n const digest = mqttHandoverStateDigest(state);\n if (digest !== response.stateDigest) throw Error(\"MQTT handover state digest mismatch\");\n if (state.application?.contract !== this.applicationState?.contract) throw Error(\"Application handover contract differs\");\n if (state.application) this.applicationState!.validateState(state.application.data);\n const byName = new Map(this.unsMqttProxies.map(proxy => [proxy.instanceName, proxy]));\n if (byName.size !== this.unsMqttProxies.length || state.proxies.length !== byName.size || state.proxies.some(p => !byName.has(p.instanceName)))\n throw Error(\"MQTT handover proxy set differs\");\n for (const snapshot of state.proxies) byName.get(snapshot.instanceName)!.validateHandoverState(snapshot);\n // Validate every cursor before importing any state or activating any subscriber.\n for (const snapshot of state.proxies) await byName.get(snapshot.instanceName)!.prepareHandoverResume(snapshot.cursor);\n // After this point an import/activation error has an unknown effect. Only\n // read-only boundary preparation may be retried on a repeated FIN.\n this.targetStateApplied = true;\n for (const snapshot of state.proxies) byName.get(snapshot.instanceName)!.importHandoverState(snapshot);\n if (state.application) await this.applicationState!.importState(state.application.data);\n for (const proxy of this.unsMqttProxies) proxy.setPublisherActive();\n await this.activateApplication();\n try {\n for (const proxy of this.unsMqttProxies) await proxy.activateHandoverResume();\n } catch {\n await this.deactivateApplication();\n throw Error(\"MQTT input activation failed; successor remains passive\");\n }\n this.acceptedStateDigest = digest;\n this.active = true;\n this.event.emit(\"handoverManager\", { active: true });\n }\n\n private async activateApplication(): Promise<void> {\n try { await this.shutdownHooks?.onActivate?.(); }\n catch {\n await this.deactivateApplication();\n throw Error(\"Application activation failed; successor remains passive\");\n }\n }\n\n private async deactivateApplication(): Promise<void> {\n this.active = false;\n try { this.shutdownHooks?.onRelease?.(); } catch { /* Keep admission closed if cleanup itself fails. */ }\n // A failed worker may not acknowledge the stop. Request passive input on\n // every peer, close outputs, and never acknowledge ownership as successful.\n for (const proxy of this.unsMqttProxies) {\n void Promise.resolve().then(() => proxy.setSubscriberPassive(true)).catch((): void => {});\n }\n await Promise.allSettled(this.unsMqttProxies.map(proxy => Promise.resolve().then(() => proxy.setPublisherPassive())));\n }\n\n private async finishSourceHandover(): Promise<void> {\n const result = await runHandoverShutdown(async () => {\n await this.sourcePreparation;\n await this.shutdownHooks?.drain();\n if (this.statefulHandover) {\n await Promise.all(this.unsMqttProxies.map(proxy => proxy.stop()));\n // The host persists this receipt synchronously before the real process\n // exit. No receipt is emitted for a partial/failed application drain.\n (process as unknown as { emit(event: string, value: unknown): boolean }).emit(\"uns-kit:mqtt-handover-drained\", {\n protocol: 2, handoverId: this.acceptedHandoverId,\n stateDigest: this.stateDigest, pendingRecords: 0,\n outputs: this.unsMqttProxies.length,\n });\n }\n }, this.shutdownHooks?.timeoutMs ?? 30_000);\n this.handoverInProgress = false;\n this.requestingHandover = false;\n if (result === \"completed\") {\n logger.info(`${this.processName} - Handover source drain completed. Exiting process.`);\n this.exitSource(0);\n } else {\n // Do not log application error text: it may contain paths, topics or credentials.\n logger.error(`${this.processName} - Handover source drain ${result}. Exiting with incomplete drain.`);\n this.exitSource(1);\n }\n }\n\n private async handleHandover(event: UnsEvents[\"input\"]): Promise<void> {\n try {\n if (event.message.length > 1100000) return;\n const response = JSON.parse(event.message.toString());\n // No downgrade: stateful peers must agree before either relinquishes ownership.\n if ((response.protocol === 2) !== this.statefulHandover) return;\n if (this.statefulHandover && (event.packet?.retain || !this.getHandoverId(response, event))) return;\n // Responder process\n // Check if the message is a handover request and publish MULTIPLE handover_subscriber messages\n if (response.type === \"handover_request\") {\n const peerId = this.getSourceProcessId(event);\n const replyTopic = event.packet?.properties?.responseTopic;\n if (this.statefulHandover && this.sourcePeerId === peerId && this.acceptedHandoverId === this.getHandoverId(response, event) && this.preparedState) {\n await this.sendPreparedState(event, this.acceptedHandoverId); return;\n }\n if (this.sourcePeerId || !this.active || !peerId || typeof replyTopic !== \"string\" || !replyTopic) return;\n if (this.statefulHandover) {\n // Reject incompatible upgrades before freezing the current owner.\n if (response.applicationContract !== this.applicationState?.contract) throw Error(\"Application handover contract differs; source remains active\");\n if (this.applicationState) {\n const preliminary = cloneApplicationHandoverState(this.applicationState.exportState());\n this.applicationState.validateState(preliminary);\n }\n const offer = mqttHandoverOfferSchema.parse(response.offer);\n const own = this.unsMqttProxies.map(proxy => proxy.getHandoverCompatibility());\n if (offer.length !== own.length || own.some(p => !offer.some(o => o.instanceName === p.instanceName && o.compatibility === p.compatibility)))\n throw Error(\"MQTT source/destination or semantic contract differs; source remains active\");\n if (this.sourceReviewInFlight) return;\n this.sourceReviewInFlight = true;\n try {\n // Hints only: actual frozen cursors are revalidated by every target\n // worker before activation. A quiet/unready source keeps admission.\n for (const proxy of this.unsMqttProxies) {\n const preview = offer.find(candidate => candidate.instanceName === proxy.instanceName)!.inputPreview;\n if (!await proxy.canPrepareHandoverInput(preview)) return;\n }\n } finally { this.sourceReviewInFlight = false; }\n if (this.sourcePeerId || !this.active) return;\n }\n this.sourcePeerId = peerId;\n this.acceptedHandoverId = this.getHandoverId(response, event);\n this.handoverInProgress = true;\n clearTimeout(this.activeTimeout);\n this.activeTimeout = undefined;\n this.sourcePreparation = this.prepareSourceHandover(response, event);\n try {\n await this.sourcePreparation;\n } catch {\n // Subscriber transfer or onRelease failed; never report successful source completion.\n logger.error(`${this.processName} - Handover source preparation failed; ownership requires review.`);\n if (!this.sourceExit && !this.statefulHandover) this.exitSource(1);\n }\n }\n\n // Requestor process\n // Check if the message is one of the handover_subscriber message in response to handover_request\n // and publish a handover_ack message\n if (response.type === \"handover_subscriber\") {\n if (this.statefulHandover) return;\n if (this.sourcePeerId) return;\n if (!this.acceptsHandoverResponse(this.getHandoverId(response, event))) return;\n // Find correct unsProxy instance for handover_subscriber and set it active\n this.unsMqttProxies.forEach((unsProxy: UnsMqttProxy) => {\n if (unsProxy.instanceName === response.instanceName) {\n unsProxy.setSubscriberActive(response.batchSize, response.referenceHash);\n }\n });\n }\n\n // Requestor process\n // Check if the message is a handover_fin at the end of handover_subscriber messages\n if (response.type === \"handover_fin\") {\n if (this.statefulHandover) {\n const id = this.getHandoverId(response, event);\n if (this.sourcePeerId || !this.requestingHandover || id !== this.handoverId || this.getSourceProcessId(event) !== this.expectedSourceId) return;\n if (this.acceptedStateDigest && response.stateDigest !== this.acceptedStateDigest) return;\n clearInterval(this.requestRetry);\n if (!this.targetPreparation) {\n const preparation = this.acceptPreparedState(response);\n this.targetPreparation = preparation;\n void preparation.catch(() => {\n if (!this.targetStateApplied && this.targetPreparation === preparation) this.targetPreparation = undefined;\n });\n }\n await this.targetPreparation;\n // Duplicate fin only replays the receipt; it never reapplies a baseline.\n if (response.stateDigest !== this.acceptedStateDigest) return;\n await this.mqttProxy.publish(event.packet.properties?.responseTopic ?? \"\", this.handoverPayload(\"handover_ack\", id,\n { stateDigest: this.acceptedStateDigest }), { retain: false, qos: 1, properties: { userProperties: this.getUserProperties(id) } });\n return;\n }\n if (this.sourcePeerId) return;\n const handoverId = this.getHandoverId(response, event);\n if (!this.acceptsHandoverResponse(handoverId)) return;\n logger.info(`${this.processName} - Received handover fin from ${event.packet?.properties?.userProperties?.processName}.`);\n\n // Maybe we should count the number of requests that were allrady made TODO\n // this.handoverInProgress = false;\n // this.requestingHandover = false;\n\n this.active = true;\n this.event.emit(\"handoverManager\", { active: this.active });\n logger.info(`${this.processName} - Handover completed.`);\n // Activate all UNS proxy instance publishers and subscribers.\n this.unsMqttProxies.forEach((unsProxy) => {\n unsProxy.setPublisherActive();\n unsProxy.setSubscriberActive();\n });\n\n // Maybe we should reply with handover_ack.\n await this.mqttProxy.publish(\n event.packet.properties?.responseTopic ?? \"\",\n this.handoverPayload(\"handover_ack\", handoverId),\n {\n retain: false,\n properties: {\n responseTopic: this.topicBuilder.getHandoverTopic(),\n userProperties: this.getUserProperties(handoverId),\n },\n },\n );\n logger.info(`${this.processName} - Handover ack message sent.`);\n }\n\n // Responder process\n // Check if the message is a handover_ack at the end of handover_fin messages\n if (response.type === \"handover_ack\") {\n if (!this.sourcePreparation || this.getSourceProcessId(event) !== this.sourcePeerId) return;\n const handoverId = this.getHandoverId(response, event);\n if (this.acceptedHandoverId && handoverId && this.acceptedHandoverId !== handoverId) {\n logger.warn(`${this.processName} - Ignoring acknowledgement for another migration.`);\n return;\n }\n if (this.statefulHandover && (handoverId !== this.acceptedHandoverId || response.stateDigest !== this.stateDigest || !this.stateDigest)) return;\n clearInterval(this.finRetry);\n logger.info(`${this.processName} - Received handover ack from ${event.packet?.properties?.userProperties?.processName}.`);\n this.sourceExit ??= this.finishSourceHandover();\n await this.sourceExit;\n }\n } catch (error) {\n logger.error(`${this.processName} - Error processing handover response: ${error.message}`);\n }\n }\n}\n"]}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Application-owned work is separate from the MQTT subscriber handover. */
|
|
2
2
|
export interface HandoverShutdownHooks {
|
|
3
|
+
/** Prepared successor: restore application owners before admitting MQTT/background work. */
|
|
4
|
+
onActivate?: () => Promise<void>;
|
|
3
5
|
/** Synchronous: stop admitting new background work when releasing ownership. */
|
|
4
6
|
onRelease?: () => void;
|
|
5
7
|
/** After target acknowledgement: finish accepted work and close writers. Never call process.exit here. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handover-shutdown.d.ts","sourceRoot":"","sources":["../../src/uns/handover-shutdown.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,0GAA0G;IAC1G,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAS5E;AAED,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1E,6FAA6F;AAC7F,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiBxH"}
|
|
1
|
+
{"version":3,"file":"handover-shutdown.d.ts","sourceRoot":"","sources":["../../src/uns/handover-shutdown.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,WAAW,qBAAqB;IACpC,4FAA4F;IAC5F,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,0GAA0G;IAC1G,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,sFAAsF;IACtF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAS5E;AAED,MAAM,MAAM,sBAAsB,GAAG,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE1E,6FAA6F;AAC7F,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiBxH"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function validateHandoverShutdown(hooks) {
|
|
2
2
|
if (!hooks)
|
|
3
3
|
return;
|
|
4
|
-
if (typeof hooks.drain !== "function" || (hooks.onRelease !== undefined && typeof hooks.onRelease !== "function")) {
|
|
4
|
+
if ((hooks.onActivate !== undefined && typeof hooks.onActivate !== "function") || typeof hooks.drain !== "function" || (hooks.onRelease !== undefined && typeof hooks.onRelease !== "function")) {
|
|
5
5
|
throw new TypeError("Invalid handover shutdown hooks.");
|
|
6
6
|
}
|
|
7
7
|
const timeout = hooks.timeoutMs ?? 30_000;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handover-shutdown.js","sourceRoot":"","sources":["../../src/uns/handover-shutdown.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"handover-shutdown.js","sourceRoot":"","sources":["../../src/uns/handover-shutdown.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,wBAAwB,CAAC,KAA6B;IACpE,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,IAAI,CAAC,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,SAAS,KAAK,UAAU,CAAC,EAAE,CAAC;QAChM,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,OAAO,EAAE,CAAC;QACnE,MAAM,IAAI,UAAU,CAAC,sEAAsE,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC;AAID,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAyB,EAAE,SAAS,GAAG,MAAM;IACrF,IAAI,KAAgD,CAAC;IACrD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACxB,OAAO,CAAC,OAAO,EAAE;iBACd,IAAI,CAAC,IAAI,CAAC;iBACV,IAAI,CACH,GAAG,EAAE,CAAC,WAAoB,EAC1B,GAAG,EAAE,CAAC,QAAiB,CACxB;YACH,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,EAAE;gBACnC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,CAAC;YAC5D,CAAC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC","sourcesContent":["/** Application-owned work is separate from the MQTT subscriber handover. */\nexport interface HandoverShutdownHooks {\n /** Prepared successor: restore application owners before admitting MQTT/background work. */\n onActivate?: () => Promise<void>;\n /** Synchronous: stop admitting new background work when releasing ownership. */\n onRelease?: () => void;\n /** After target acknowledgement: finish accepted work and close writers. Never call process.exit here. */\n drain: () => Promise<void>;\n /** Total time for remaining proxy stops and application drain; default 30 seconds. */\n timeoutMs?: number;\n}\n\nexport function validateHandoverShutdown(hooks?: HandoverShutdownHooks): void {\n if (!hooks) return;\n if ((hooks.onActivate !== undefined && typeof hooks.onActivate !== \"function\") || typeof hooks.drain !== \"function\" || (hooks.onRelease !== undefined && typeof hooks.onRelease !== \"function\")) {\n throw new TypeError(\"Invalid handover shutdown hooks.\");\n }\n const timeout = hooks.timeoutMs ?? 30_000;\n if (!Number.isInteger(timeout) || timeout < 1 || timeout > 300_000) {\n throw new RangeError(\"Handover shutdown timeout must be between 1 and 300000 milliseconds.\");\n }\n}\n\nexport type HandoverShutdownResult = \"completed\" | \"failed\" | \"timed-out\";\n\n/** A timeout does not cancel IO or prove durability. The process owner must exit nonzero. */\nexport async function runHandoverShutdown(work: () => Promise<void>, timeoutMs = 30_000): Promise<HandoverShutdownResult> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n Promise.resolve()\n .then(work)\n .then(\n () => \"completed\" as const,\n () => \"failed\" as const,\n ),\n new Promise<\"timed-out\">((resolve) => {\n timer = setTimeout(() => resolve(\"timed-out\"), timeoutMs);\n }),\n ]);\n } finally {\n if (timer) clearTimeout(timer);\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { MqttPublishQueueOptions } from "../uns-mqtt/publish-queue-contract.js";
|
|
2
|
+
import type { ApplicationHandoverState } from "../runtime/application-handover-state.js";
|
|
2
3
|
import type { HandoverShutdownHooks } from "./handover-shutdown.js";
|
|
3
4
|
import { UnsAttributeType } from "../graphql/schema.js";
|
|
4
5
|
import { MeasurementUnit } from "./uns-measurements.js";
|
|
@@ -86,6 +87,10 @@ export interface IUnsParameters {
|
|
|
86
87
|
defaultPublishOptions?: IMqttPublishOptions;
|
|
87
88
|
}
|
|
88
89
|
export interface IUnsProcessParameters {
|
|
90
|
+
/** Wait for explicit application readiness before initial ownership. */
|
|
91
|
+
deferHandoverUntilReady?: boolean;
|
|
92
|
+
/** Optional bounded application RAM state transferred with the reviewed SDK handover. */
|
|
93
|
+
handoverState?: ApplicationHandoverState;
|
|
89
94
|
/** Optional application drain after a cooperative handover. Register before creating proxies. */
|
|
90
95
|
handoverShutdown?: HandoverShutdownHooks;
|
|
91
96
|
processName: string;
|
|
@@ -140,6 +145,7 @@ export interface UnsEvents {
|
|
|
140
145
|
instanceName: string;
|
|
141
146
|
batchSize: number;
|
|
142
147
|
referenceHash: string;
|
|
148
|
+
processedTail?: string[];
|
|
143
149
|
};
|
|
144
150
|
cronEvent: {
|
|
145
151
|
event?: string;
|