@rudderstack/integrations-lib 0.2.38 → 0.2.40
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/build/cluster/examples.d.ts +2 -0
- package/build/cluster/examples.d.ts.map +1 -0
- package/build/cluster/examples.js +150 -0
- package/build/cluster/index.d.ts +3 -0
- package/build/cluster/index.d.ts.map +1 -0
- package/build/cluster/index.js +6 -0
- package/build/cluster/manager.d.ts +143 -0
- package/build/cluster/manager.d.ts.map +1 -0
- package/build/cluster/manager.js +457 -0
- package/build/cluster/types.d.ts +78 -0
- package/build/cluster/types.d.ts.map +1 -0
- package/build/cluster/types.js +3 -0
- package/build/cluster/utils.d.ts +20 -0
- package/build/cluster/utils.d.ts.map +1 -0
- package/build/cluster/utils.js +106 -0
- package/build/index.d.ts +1 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../../src/cluster/examples.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
/* eslint-disable require-await */
|
|
40
|
+
const cluster_1 = __importDefault(require("cluster"));
|
|
41
|
+
const manager_1 = require("./manager");
|
|
42
|
+
const logger = __importStar(require("../logger"));
|
|
43
|
+
async function normalExample() {
|
|
44
|
+
const manager = new manager_1.ClusterManager({
|
|
45
|
+
numWorkers: 2,
|
|
46
|
+
pingFrequency: 1000, // Check every second
|
|
47
|
+
pingTimeout: 5000, // 5 seconds for a worker to respond
|
|
48
|
+
shutdownTimeout: 5000, // 5 seconds for graceful shutdown
|
|
49
|
+
primaryFn: async () => {
|
|
50
|
+
setTimeout(() => {
|
|
51
|
+
logger.info('Primary process shutting down...');
|
|
52
|
+
manager.shutdown('manual shutdown');
|
|
53
|
+
}, 10000);
|
|
54
|
+
},
|
|
55
|
+
primaryShutdownFn: async (signal) => {
|
|
56
|
+
logger.info(`Primary process shutting down due to signal: ${signal}`);
|
|
57
|
+
},
|
|
58
|
+
workerFn: async () => {
|
|
59
|
+
// Simulate some work
|
|
60
|
+
setInterval(() => {
|
|
61
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} is doing work`);
|
|
62
|
+
}, 1000);
|
|
63
|
+
},
|
|
64
|
+
workerShutdownFn: async (signal) => {
|
|
65
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} shutting down due to signal: ${signal}`);
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
await manager.start();
|
|
69
|
+
}
|
|
70
|
+
async function stuckExample() {
|
|
71
|
+
let stuckCounter = 0;
|
|
72
|
+
const manager = new manager_1.ClusterManager({
|
|
73
|
+
numWorkers: 2,
|
|
74
|
+
pingFrequency: 1000, // Check every second
|
|
75
|
+
pingTimeout: 5000, // 5 seconds for a worker to respond
|
|
76
|
+
shutdownTimeout: 5000, // 5 seconds for graceful shutdown
|
|
77
|
+
stuckWorkerRespawnFunc: (worker) => {
|
|
78
|
+
stuckCounter += 1;
|
|
79
|
+
if (stuckCounter > 3) {
|
|
80
|
+
logger.info(`Stuck worker detected: ${worker.id}. Not respawning anymore.`);
|
|
81
|
+
return false; // Stop respawning after 3 stuck workers
|
|
82
|
+
}
|
|
83
|
+
logger.info(`Stuck worker detected: ${worker.id}. Respawning...`);
|
|
84
|
+
return true; // Respawn the worker
|
|
85
|
+
},
|
|
86
|
+
primaryFn: async () => {
|
|
87
|
+
logger.info('Primary process started');
|
|
88
|
+
},
|
|
89
|
+
primaryShutdownFn: async (signal) => {
|
|
90
|
+
logger.info(`Primary process shutting down due to signal: ${signal}`);
|
|
91
|
+
},
|
|
92
|
+
workerFn: async () => {
|
|
93
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} will simulate being stuck`);
|
|
94
|
+
// eslint-disable-next-line no-constant-condition
|
|
95
|
+
while (true) {
|
|
96
|
+
// Simulate a stuck worker
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
workerShutdownFn: async (signal) => {
|
|
100
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} shutting down due to signal: ${signal}`);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
await manager.start();
|
|
104
|
+
}
|
|
105
|
+
async function killExample() {
|
|
106
|
+
const manager = new manager_1.ClusterManager({
|
|
107
|
+
numWorkers: 2,
|
|
108
|
+
pingFrequency: 1000, // Check every second
|
|
109
|
+
pingTimeout: 5000, // 5 seconds for a worker to respond
|
|
110
|
+
shutdownTimeout: 5000, // 5 seconds for graceful shutdown
|
|
111
|
+
restartMaxTimes: 3, // Restart a worker up to 3 times
|
|
112
|
+
primaryFn: async () => {
|
|
113
|
+
logger.info('Primary process started');
|
|
114
|
+
},
|
|
115
|
+
primaryShutdownFn: async (signal) => {
|
|
116
|
+
logger.info(`Primary process shutting down due to signal: ${signal}`);
|
|
117
|
+
},
|
|
118
|
+
workerFn: async () => {
|
|
119
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} started and will crash after 5 seconds`);
|
|
120
|
+
// eslint-disable-next-line no-constant-condition
|
|
121
|
+
setTimeout(() => {
|
|
122
|
+
logger.info(`Killing worker ${cluster_1.default.worker?.id} process`);
|
|
123
|
+
process.exit(1); // Simulate a worker crash
|
|
124
|
+
}, 5000); // Kill the worker after 5 seconds
|
|
125
|
+
},
|
|
126
|
+
workerShutdownFn: async (signal) => {
|
|
127
|
+
logger.info(`Worker ${cluster_1.default.worker?.id} shutting down due to signal: ${signal}`);
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
await manager.start();
|
|
131
|
+
}
|
|
132
|
+
// to run use: npx ts-node src/cluster/examples.ts [normal|stuck|kill]
|
|
133
|
+
if (require.main === module) {
|
|
134
|
+
const mode = process.argv[2] || 'normal';
|
|
135
|
+
let run;
|
|
136
|
+
if (mode === 'stuck') {
|
|
137
|
+
run = stuckExample;
|
|
138
|
+
}
|
|
139
|
+
else if (mode === 'kill') {
|
|
140
|
+
run = killExample;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
run = normalExample;
|
|
144
|
+
}
|
|
145
|
+
run().catch((err) => {
|
|
146
|
+
logger.error(err);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhhbXBsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2x1c3Rlci9leGFtcGxlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGtDQUFrQztBQUNsQyxzREFBOEI7QUFDOUIsdUNBQTJDO0FBQzNDLGtEQUFvQztBQUVwQyxLQUFLLFVBQVUsYUFBYTtJQUMxQixNQUFNLE9BQU8sR0FBRyxJQUFJLHdCQUFjLENBQUM7UUFDakMsVUFBVSxFQUFFLENBQUM7UUFDYixhQUFhLEVBQUUsSUFBSSxFQUFFLHFCQUFxQjtRQUMxQyxXQUFXLEVBQUUsSUFBSSxFQUFFLG9DQUFvQztRQUN2RCxlQUFlLEVBQUUsSUFBSSxFQUFFLGtDQUFrQztRQUN6RCxTQUFTLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDcEIsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxNQUFNLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxDQUFDLENBQUM7Z0JBQ2hELE9BQU8sQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FBQztZQUN0QyxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDWixDQUFDO1FBQ0QsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2xDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0RBQWdELE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELFFBQVEsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNuQixxQkFBcUI7WUFDckIsV0FBVyxDQUFDLEdBQUcsRUFBRTtnQkFDZixNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsaUJBQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1lBQzVELENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNYLENBQUM7UUFDRCxnQkFBZ0IsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7WUFDakMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLGlCQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsaUNBQWlDLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDckYsQ0FBQztLQUNGLENBQUMsQ0FBQztJQUNILE1BQU0sT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQ3hCLENBQUM7QUFFRCxLQUFLLFVBQVUsWUFBWTtJQUN6QixJQUFJLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDckIsTUFBTSxPQUFPLEdBQUcsSUFBSSx3QkFBYyxDQUFDO1FBQ2pDLFVBQVUsRUFBRSxDQUFDO1FBQ2IsYUFBYSxFQUFFLElBQUksRUFBRSxxQkFBcUI7UUFDMUMsV0FBVyxFQUFFLElBQUksRUFBRSxvQ0FBb0M7UUFDdkQsZUFBZSxFQUFFLElBQUksRUFBRSxrQ0FBa0M7UUFDekQsc0JBQXNCLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUNqQyxZQUFZLElBQUksQ0FBQyxDQUFDO1lBQ2xCLElBQUksWUFBWSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNyQixNQUFNLENBQUMsSUFBSSxDQUFDLDBCQUEwQixNQUFNLENBQUMsRUFBRSwyQkFBMkIsQ0FBQyxDQUFDO2dCQUM1RSxPQUFPLEtBQUssQ0FBQyxDQUFDLHdDQUF3QztZQUN4RCxDQUFDO1lBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQywwQkFBMEIsTUFBTSxDQUFDLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztZQUNsRSxPQUFPLElBQUksQ0FBQyxDQUFDLHFCQUFxQjtRQUNwQyxDQUFDO1FBQ0QsU0FBUyxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ3BCLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBQ0QsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2xDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZ0RBQWdELE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELFFBQVEsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNuQixNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsaUJBQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSw0QkFBNEIsQ0FBQyxDQUFDO1lBQ3RFLGlEQUFpRDtZQUNqRCxPQUFPLElBQUksRUFBRSxDQUFDO2dCQUNaLDBCQUEwQjtZQUM1QixDQUFDO1FBQ0gsQ0FBQztRQUNELGdCQUFnQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNqQyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsaUJBQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxpQ0FBaUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUNyRixDQUFDO0tBQ0YsQ0FBQyxDQUFDO0lBQ0gsTUFBTSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7QUFDeEIsQ0FBQztBQUVELEtBQUssVUFBVSxXQUFXO0lBQ3hCLE1BQU0sT0FBTyxHQUFHLElBQUksd0JBQWMsQ0FBQztRQUNqQyxVQUFVLEVBQUUsQ0FBQztRQUNiLGFBQWEsRUFBRSxJQUFJLEVBQUUscUJBQXFCO1FBQzFDLFdBQVcsRUFBRSxJQUFJLEVBQUUsb0NBQW9DO1FBQ3ZELGVBQWUsRUFBRSxJQUFJLEVBQUUsa0NBQWtDO1FBQ3pELGVBQWUsRUFBRSxDQUFDLEVBQUUsaUNBQWlDO1FBQ3JELFNBQVMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLHlCQUF5QixDQUFDLENBQUM7UUFDekMsQ0FBQztRQUNELGlCQUFpQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUNsQyxNQUFNLENBQUMsSUFBSSxDQUFDLGdEQUFnRCxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3hFLENBQUM7UUFDRCxRQUFRLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDbkIsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLGlCQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUseUNBQXlDLENBQUMsQ0FBQztZQUNuRixpREFBaUQ7WUFDakQsVUFBVSxDQUFDLEdBQUcsRUFBRTtnQkFDZCxNQUFNLENBQUMsSUFBSSxDQUFDLGtCQUFrQixpQkFBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLFVBQVUsQ0FBQyxDQUFDO2dCQUM1RCxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsMEJBQTBCO1lBQzdDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLGtDQUFrQztRQUM5QyxDQUFDO1FBQ0QsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ2pDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxpQkFBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLGlDQUFpQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQ3JGLENBQUM7S0FDRixDQUFDLENBQUM7SUFDSCxNQUFNLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUN4QixDQUFDO0FBRUQsc0VBQXNFO0FBQ3RFLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztJQUM1QixNQUFNLElBQUksR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLFFBQVEsQ0FBQztJQUN6QyxJQUFJLEdBQUcsQ0FBQztJQUNSLElBQUksSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO1FBQ3JCLEdBQUcsR0FBRyxZQUFZLENBQUM7SUFDckIsQ0FBQztTQUFNLElBQUksSUFBSSxLQUFLLE1BQU0sRUFBRSxDQUFDO1FBQzNCLEdBQUcsR0FBRyxXQUFXLENBQUM7SUFDcEIsQ0FBQztTQUFNLENBQUM7UUFDTixHQUFHLEdBQUcsYUFBYSxDQUFDO0lBQ3RCLENBQUM7SUFDRCxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRTtRQUNsQixNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgcmVxdWlyZS1hd2FpdCAqL1xuaW1wb3J0IGNsdXN0ZXIgZnJvbSAnY2x1c3Rlcic7XG5pbXBvcnQgeyBDbHVzdGVyTWFuYWdlciB9IGZyb20gJy4vbWFuYWdlcic7XG5pbXBvcnQgKiBhcyBsb2dnZXIgZnJvbSAnLi4vbG9nZ2VyJztcblxuYXN5bmMgZnVuY3Rpb24gbm9ybWFsRXhhbXBsZSgpIHtcbiAgY29uc3QgbWFuYWdlciA9IG5ldyBDbHVzdGVyTWFuYWdlcih7XG4gICAgbnVtV29ya2VyczogMixcbiAgICBwaW5nRnJlcXVlbmN5OiAxMDAwLCAvLyBDaGVjayBldmVyeSBzZWNvbmRcbiAgICBwaW5nVGltZW91dDogNTAwMCwgLy8gNSBzZWNvbmRzIGZvciBhIHdvcmtlciB0byByZXNwb25kXG4gICAgc2h1dGRvd25UaW1lb3V0OiA1MDAwLCAvLyA1IHNlY29uZHMgZm9yIGdyYWNlZnVsIHNodXRkb3duXG4gICAgcHJpbWFyeUZuOiBhc3luYyAoKSA9PiB7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgbG9nZ2VyLmluZm8oJ1ByaW1hcnkgcHJvY2VzcyBzaHV0dGluZyBkb3duLi4uJyk7XG4gICAgICAgIG1hbmFnZXIuc2h1dGRvd24oJ21hbnVhbCBzaHV0ZG93bicpO1xuICAgICAgfSwgMTAwMDApO1xuICAgIH0sXG4gICAgcHJpbWFyeVNodXRkb3duRm46IGFzeW5jIChzaWduYWwpID0+IHtcbiAgICAgIGxvZ2dlci5pbmZvKGBQcmltYXJ5IHByb2Nlc3Mgc2h1dHRpbmcgZG93biBkdWUgdG8gc2lnbmFsOiAke3NpZ25hbH1gKTtcbiAgICB9LFxuICAgIHdvcmtlckZuOiBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBTaW11bGF0ZSBzb21lIHdvcmtcbiAgICAgIHNldEludGVydmFsKCgpID0+IHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFdvcmtlciAke2NsdXN0ZXIud29ya2VyPy5pZH0gaXMgZG9pbmcgd29ya2ApO1xuICAgICAgfSwgMTAwMCk7XG4gICAgfSxcbiAgICB3b3JrZXJTaHV0ZG93bkZuOiBhc3luYyAoc2lnbmFsKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbyhgV29ya2VyICR7Y2x1c3Rlci53b3JrZXI/LmlkfSBzaHV0dGluZyBkb3duIGR1ZSB0byBzaWduYWw6ICR7c2lnbmFsfWApO1xuICAgIH0sXG4gIH0pO1xuICBhd2FpdCBtYW5hZ2VyLnN0YXJ0KCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHN0dWNrRXhhbXBsZSgpIHtcbiAgbGV0IHN0dWNrQ291bnRlciA9IDA7XG4gIGNvbnN0IG1hbmFnZXIgPSBuZXcgQ2x1c3Rlck1hbmFnZXIoe1xuICAgIG51bVdvcmtlcnM6IDIsXG4gICAgcGluZ0ZyZXF1ZW5jeTogMTAwMCwgLy8gQ2hlY2sgZXZlcnkgc2Vjb25kXG4gICAgcGluZ1RpbWVvdXQ6IDUwMDAsIC8vIDUgc2Vjb25kcyBmb3IgYSB3b3JrZXIgdG8gcmVzcG9uZFxuICAgIHNodXRkb3duVGltZW91dDogNTAwMCwgLy8gNSBzZWNvbmRzIGZvciBncmFjZWZ1bCBzaHV0ZG93blxuICAgIHN0dWNrV29ya2VyUmVzcGF3bkZ1bmM6ICh3b3JrZXIpID0+IHtcbiAgICAgIHN0dWNrQ291bnRlciArPSAxO1xuICAgICAgaWYgKHN0dWNrQ291bnRlciA+IDMpIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYFN0dWNrIHdvcmtlciBkZXRlY3RlZDogJHt3b3JrZXIuaWR9LiBOb3QgcmVzcGF3bmluZyBhbnltb3JlLmApO1xuICAgICAgICByZXR1cm4gZmFsc2U7IC8vIFN0b3AgcmVzcGF3bmluZyBhZnRlciAzIHN0dWNrIHdvcmtlcnNcbiAgICAgIH1cbiAgICAgIGxvZ2dlci5pbmZvKGBTdHVjayB3b3JrZXIgZGV0ZWN0ZWQ6ICR7d29ya2VyLmlkfS4gUmVzcGF3bmluZy4uLmApO1xuICAgICAgcmV0dXJuIHRydWU7IC8vIFJlc3Bhd24gdGhlIHdvcmtlclxuICAgIH0sXG4gICAgcHJpbWFyeUZuOiBhc3luYyAoKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbygnUHJpbWFyeSBwcm9jZXNzIHN0YXJ0ZWQnKTtcbiAgICB9LFxuICAgIHByaW1hcnlTaHV0ZG93bkZuOiBhc3luYyAoc2lnbmFsKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbyhgUHJpbWFyeSBwcm9jZXNzIHNodXR0aW5nIGRvd24gZHVlIHRvIHNpZ25hbDogJHtzaWduYWx9YCk7XG4gICAgfSxcbiAgICB3b3JrZXJGbjogYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oYFdvcmtlciAke2NsdXN0ZXIud29ya2VyPy5pZH0gd2lsbCBzaW11bGF0ZSBiZWluZyBzdHVja2ApO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnN0YW50LWNvbmRpdGlvblxuICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgLy8gU2ltdWxhdGUgYSBzdHVjayB3b3JrZXJcbiAgICAgIH1cbiAgICB9LFxuICAgIHdvcmtlclNodXRkb3duRm46IGFzeW5jIChzaWduYWwpID0+IHtcbiAgICAgIGxvZ2dlci5pbmZvKGBXb3JrZXIgJHtjbHVzdGVyLndvcmtlcj8uaWR9IHNodXR0aW5nIGRvd24gZHVlIHRvIHNpZ25hbDogJHtzaWduYWx9YCk7XG4gICAgfSxcbiAgfSk7XG4gIGF3YWl0IG1hbmFnZXIuc3RhcnQoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24ga2lsbEV4YW1wbGUoKSB7XG4gIGNvbnN0IG1hbmFnZXIgPSBuZXcgQ2x1c3Rlck1hbmFnZXIoe1xuICAgIG51bVdvcmtlcnM6IDIsXG4gICAgcGluZ0ZyZXF1ZW5jeTogMTAwMCwgLy8gQ2hlY2sgZXZlcnkgc2Vjb25kXG4gICAgcGluZ1RpbWVvdXQ6IDUwMDAsIC8vIDUgc2Vjb25kcyBmb3IgYSB3b3JrZXIgdG8gcmVzcG9uZFxuICAgIHNodXRkb3duVGltZW91dDogNTAwMCwgLy8gNSBzZWNvbmRzIGZvciBncmFjZWZ1bCBzaHV0ZG93blxuICAgIHJlc3RhcnRNYXhUaW1lczogMywgLy8gUmVzdGFydCBhIHdvcmtlciB1cCB0byAzIHRpbWVzXG4gICAgcHJpbWFyeUZuOiBhc3luYyAoKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbygnUHJpbWFyeSBwcm9jZXNzIHN0YXJ0ZWQnKTtcbiAgICB9LFxuICAgIHByaW1hcnlTaHV0ZG93bkZuOiBhc3luYyAoc2lnbmFsKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbyhgUHJpbWFyeSBwcm9jZXNzIHNodXR0aW5nIGRvd24gZHVlIHRvIHNpZ25hbDogJHtzaWduYWx9YCk7XG4gICAgfSxcbiAgICB3b3JrZXJGbjogYXN5bmMgKCkgPT4ge1xuICAgICAgbG9nZ2VyLmluZm8oYFdvcmtlciAke2NsdXN0ZXIud29ya2VyPy5pZH0gc3RhcnRlZCBhbmQgd2lsbCBjcmFzaCBhZnRlciA1IHNlY29uZHNgKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zdGFudC1jb25kaXRpb25cbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBsb2dnZXIuaW5mbyhgS2lsbGluZyB3b3JrZXIgJHtjbHVzdGVyLndvcmtlcj8uaWR9IHByb2Nlc3NgKTtcbiAgICAgICAgcHJvY2Vzcy5leGl0KDEpOyAvLyBTaW11bGF0ZSBhIHdvcmtlciBjcmFzaFxuICAgICAgfSwgNTAwMCk7IC8vIEtpbGwgdGhlIHdvcmtlciBhZnRlciA1IHNlY29uZHNcbiAgICB9LFxuICAgIHdvcmtlclNodXRkb3duRm46IGFzeW5jIChzaWduYWwpID0+IHtcbiAgICAgIGxvZ2dlci5pbmZvKGBXb3JrZXIgJHtjbHVzdGVyLndvcmtlcj8uaWR9IHNodXR0aW5nIGRvd24gZHVlIHRvIHNpZ25hbDogJHtzaWduYWx9YCk7XG4gICAgfSxcbiAgfSk7XG4gIGF3YWl0IG1hbmFnZXIuc3RhcnQoKTtcbn1cblxuLy8gdG8gcnVuIHVzZTogbnB4IHRzLW5vZGUgc3JjL2NsdXN0ZXIvZXhhbXBsZXMudHMgW25vcm1hbHxzdHVja3xraWxsXVxuaWYgKHJlcXVpcmUubWFpbiA9PT0gbW9kdWxlKSB7XG4gIGNvbnN0IG1vZGUgPSBwcm9jZXNzLmFyZ3ZbMl0gfHwgJ25vcm1hbCc7XG4gIGxldCBydW47XG4gIGlmIChtb2RlID09PSAnc3R1Y2snKSB7XG4gICAgcnVuID0gc3R1Y2tFeGFtcGxlO1xuICB9IGVsc2UgaWYgKG1vZGUgPT09ICdraWxsJykge1xuICAgIHJ1biA9IGtpbGxFeGFtcGxlO1xuICB9IGVsc2Uge1xuICAgIHJ1biA9IG5vcm1hbEV4YW1wbGU7XG4gIH1cbiAgcnVuKCkuY2F0Y2goKGVycikgPT4ge1xuICAgIGxvZ2dlci5lcnJvcihlcnIpO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG59XG4iXX0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cluster/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClE,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,WAAW,EACX,eAAe,EACf,UAAU,GACX,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClusterManager = void 0;
|
|
4
|
+
var manager_1 = require("./manager");
|
|
5
|
+
Object.defineProperty(exports, "ClusterManager", { enumerable: true, get: function () { return manager_1.ClusterManager; } });
|
|
6
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2x1c3Rlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxxQ0FBa0U7QUFBekQseUdBQUEsY0FBYyxPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IHsgQ2x1c3Rlck1hbmFnZXIsIENsdXN0ZXJNYW5hZ2VyRW1pdHRlciB9IGZyb20gJy4vbWFuYWdlcic7XG5leHBvcnQgdHlwZSB7XG4gIENsdXN0ZXJNYW5hZ2VyT3B0aW9ucyxcbiAgQ2x1c3Rlck1hbmFnZXJFdmVudHMsXG4gIFdvcmtlclN0YXRlLFxuICBQaW5nTWVzc2FnZSxcbiAgUG9uZ01lc3NhZ2UsXG4gIFNodXRkb3duTWVzc2FnZSxcbiAgSVBDTWVzc2FnZSxcbn0gZnJvbSAnLi90eXBlcyc7XG4iXX0=
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ClusterManagerOptions, ClusterManagerEvents } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* ClusterManager - A cluster lifecycle management system
|
|
5
|
+
*
|
|
6
|
+
* The manager supports the following features:
|
|
7
|
+
* - Graceful shutdown with configurable timeout
|
|
8
|
+
* - Worker health monitoring with ping/pong mechanism
|
|
9
|
+
* - Automatic worker restart with configurable limits
|
|
10
|
+
* - Signal handling for shutdown triggers
|
|
11
|
+
* - Flexible primary and worker function handlers
|
|
12
|
+
*/
|
|
13
|
+
export declare class ClusterManager extends EventEmitter {
|
|
14
|
+
private readonly options;
|
|
15
|
+
private readonly workers;
|
|
16
|
+
private started;
|
|
17
|
+
private isShuttingDown;
|
|
18
|
+
private shutdownPromise;
|
|
19
|
+
private healthCheckInterval;
|
|
20
|
+
private signalHandlers;
|
|
21
|
+
constructor(options?: ClusterManagerOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Starts the cluster manager
|
|
24
|
+
* In primary process: starts workers and health monitoring
|
|
25
|
+
* In worker process: executes worker function
|
|
26
|
+
*/
|
|
27
|
+
start(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Initiates graceful shutdown of the cluster
|
|
30
|
+
*/
|
|
31
|
+
shutdown(signal?: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Sets up signal handlers for graceful shutdown
|
|
34
|
+
*/
|
|
35
|
+
private setupSignalHandlers;
|
|
36
|
+
/**
|
|
37
|
+
* Removes signal handlers
|
|
38
|
+
*/
|
|
39
|
+
private removeSignalHandlers;
|
|
40
|
+
/**
|
|
41
|
+
* Starts the primary process
|
|
42
|
+
*/
|
|
43
|
+
private startPrimary;
|
|
44
|
+
/**
|
|
45
|
+
* Starts a worker process
|
|
46
|
+
*/
|
|
47
|
+
private startWorker;
|
|
48
|
+
/**
|
|
49
|
+
* Sets up cluster event handlers for the primary process
|
|
50
|
+
*/
|
|
51
|
+
private setupClusterEventHandlers;
|
|
52
|
+
/**
|
|
53
|
+
* Sets up IPC message handlers for worker processes
|
|
54
|
+
*/
|
|
55
|
+
private setupWorkerMessageHandlers;
|
|
56
|
+
/**
|
|
57
|
+
* Spawns a new worker and sets up its state
|
|
58
|
+
*/
|
|
59
|
+
private spawnWorker;
|
|
60
|
+
/**
|
|
61
|
+
* Handles messages from workers
|
|
62
|
+
*/
|
|
63
|
+
private handleWorkerMessage;
|
|
64
|
+
/**
|
|
65
|
+
* Handles ping messages in worker processes
|
|
66
|
+
*/
|
|
67
|
+
private handleWorkerPing;
|
|
68
|
+
/**
|
|
69
|
+
* Starts health monitoring for all workers
|
|
70
|
+
*/
|
|
71
|
+
private startHealthMonitoring;
|
|
72
|
+
/**
|
|
73
|
+
* Stops health monitoring
|
|
74
|
+
*/
|
|
75
|
+
private stopHealthMonitoring;
|
|
76
|
+
/**
|
|
77
|
+
* Performs health check on all workers
|
|
78
|
+
*/
|
|
79
|
+
private performHealthCheck;
|
|
80
|
+
/**
|
|
81
|
+
* Sends a ping message to a worker
|
|
82
|
+
*/
|
|
83
|
+
private sendPingToWorker;
|
|
84
|
+
/**
|
|
85
|
+
* Handles a stuck worker
|
|
86
|
+
*/
|
|
87
|
+
private handleStuckWorker;
|
|
88
|
+
/**
|
|
89
|
+
* Handles worker exit events
|
|
90
|
+
*/
|
|
91
|
+
private handleWorkerExit;
|
|
92
|
+
private getWorkerId;
|
|
93
|
+
private getCurrentWorkerId;
|
|
94
|
+
/**
|
|
95
|
+
* Handles unexpected worker exits with restart logic
|
|
96
|
+
*/
|
|
97
|
+
private handleUnexpectedWorkerExit;
|
|
98
|
+
/**
|
|
99
|
+
* Shuts down the primary process
|
|
100
|
+
*/
|
|
101
|
+
private shutdownPrimary;
|
|
102
|
+
/**
|
|
103
|
+
* Shuts down all workers gracefully
|
|
104
|
+
*/
|
|
105
|
+
private shutdownAllWorkers;
|
|
106
|
+
/**
|
|
107
|
+
* Waits for all workers to exit
|
|
108
|
+
*/
|
|
109
|
+
private waitForAllWorkersToExit;
|
|
110
|
+
/**
|
|
111
|
+
* Force kills all remaining workers
|
|
112
|
+
*/
|
|
113
|
+
private forceKillAllWorkers;
|
|
114
|
+
/**
|
|
115
|
+
* Shuts down a worker process
|
|
116
|
+
*/
|
|
117
|
+
private shutdownWorker;
|
|
118
|
+
/**
|
|
119
|
+
* Gets the current number of active workers
|
|
120
|
+
*/
|
|
121
|
+
getWorkerCount(): number;
|
|
122
|
+
/**
|
|
123
|
+
* Gets information about all workers
|
|
124
|
+
*/
|
|
125
|
+
getWorkerInfo(): Array<{
|
|
126
|
+
id: number;
|
|
127
|
+
pid: number;
|
|
128
|
+
restartCount: number;
|
|
129
|
+
}>;
|
|
130
|
+
/**
|
|
131
|
+
* Checks if the cluster is currently started
|
|
132
|
+
*/
|
|
133
|
+
isStarted(): boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Checks if the cluster is currently shutting down
|
|
136
|
+
*/
|
|
137
|
+
isShutdown(): boolean;
|
|
138
|
+
}
|
|
139
|
+
export interface ClusterManagerEmitter {
|
|
140
|
+
on<K extends keyof ClusterManagerEvents>(event: K, listener: ClusterManagerEvents[K]): this;
|
|
141
|
+
emit<K extends keyof ClusterManagerEvents>(event: K, ...args: Parameters<ClusterManagerEvents[K]>): boolean;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/cluster/manager.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EAMrB,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;GASG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAE1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkC;IAE1D,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,eAAe,CAA8B;IAErD,OAAO,CAAC,mBAAmB,CAA+B;IAE1D,OAAO,CAAC,cAAc,CAAyC;gBAEnD,OAAO,GAAE,qBAA0B;IAM/C;;;;OAIG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;OAEG;IACI,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB/C;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAO5B;;OAEG;YACW,YAAY;IAqB1B;;OAEG;YACW,WAAW;IAUzB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAWjC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;OAEG;IACH,OAAO,CAAC,WAAW;IAuBnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAO5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkB1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAiCzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,kBAAkB;IAM1B;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAsBlC;;OAEG;YACW,eAAe;IA2B7B;;OAEG;YACW,kBAAkB;IAwChC;;OAEG;YACW,uBAAuB;IAOrC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;OAEG;YACW,cAAc;IAwB5B;;OAEG;IACI,cAAc,IAAI,MAAM;IAI/B;;OAEG;IACI,aAAa,IAAI,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAQhF;;OAEG;IACI,SAAS,IAAI,OAAO;IAI3B;;OAEG;IACI,UAAU,IAAI,OAAO;CAG7B;AAGD,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,CAAC,SAAS,MAAM,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAC5F,IAAI,CAAC,CAAC,SAAS,MAAM,oBAAoB,EACvC,KAAK,EAAE,CAAC,EACR,GAAG,IAAI,EAAE,UAAU,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,GAC3C,OAAO,CAAC;CACZ"}
|
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ClusterManager = void 0;
|
|
37
|
+
const events_1 = require("events");
|
|
38
|
+
const logger = __importStar(require("../logger"));
|
|
39
|
+
const utils_1 = require("./utils");
|
|
40
|
+
/**
|
|
41
|
+
* ClusterManager - A cluster lifecycle management system
|
|
42
|
+
*
|
|
43
|
+
* The manager supports the following features:
|
|
44
|
+
* - Graceful shutdown with configurable timeout
|
|
45
|
+
* - Worker health monitoring with ping/pong mechanism
|
|
46
|
+
* - Automatic worker restart with configurable limits
|
|
47
|
+
* - Signal handling for shutdown triggers
|
|
48
|
+
* - Flexible primary and worker function handlers
|
|
49
|
+
*/
|
|
50
|
+
class ClusterManager extends events_1.EventEmitter {
|
|
51
|
+
constructor(options = {}) {
|
|
52
|
+
super();
|
|
53
|
+
this.workers = new Map();
|
|
54
|
+
this.started = false;
|
|
55
|
+
this.isShuttingDown = false;
|
|
56
|
+
this.shutdownPromise = null;
|
|
57
|
+
this.healthCheckInterval = null;
|
|
58
|
+
this.signalHandlers = new Map();
|
|
59
|
+
this.options = (0, utils_1.validateAndDefaultOptions)(options);
|
|
60
|
+
this.setupSignalHandlers();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Starts the cluster manager
|
|
64
|
+
* In primary process: starts workers and health monitoring
|
|
65
|
+
* In worker process: executes worker function
|
|
66
|
+
*/
|
|
67
|
+
async start() {
|
|
68
|
+
if (this.options.cluster.isPrimary) {
|
|
69
|
+
await this.startPrimary();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
await this.startWorker();
|
|
73
|
+
}
|
|
74
|
+
this.started = true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Initiates graceful shutdown of the cluster
|
|
78
|
+
*/
|
|
79
|
+
shutdown(signal) {
|
|
80
|
+
if (!this.started) {
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
}
|
|
83
|
+
if (this.shutdownPromise) {
|
|
84
|
+
return this.shutdownPromise;
|
|
85
|
+
}
|
|
86
|
+
this.isShuttingDown = true;
|
|
87
|
+
this.emit('shutdown:started', signal);
|
|
88
|
+
if (this.options.cluster.isPrimary) {
|
|
89
|
+
this.shutdownPromise = this.shutdownPrimary(signal);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.shutdownPromise = this.shutdownWorker(signal);
|
|
93
|
+
}
|
|
94
|
+
return this.shutdownPromise;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Sets up signal handlers for graceful shutdown
|
|
98
|
+
*/
|
|
99
|
+
setupSignalHandlers() {
|
|
100
|
+
this.options.shutdownSignals.forEach((signal) => {
|
|
101
|
+
const handler = () => {
|
|
102
|
+
this.shutdown(signal);
|
|
103
|
+
};
|
|
104
|
+
this.signalHandlers.set(signal, handler);
|
|
105
|
+
process.on(signal, handler);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Removes signal handlers
|
|
110
|
+
*/
|
|
111
|
+
removeSignalHandlers() {
|
|
112
|
+
Array.from(this.signalHandlers.entries()).forEach(([signal, handler]) => {
|
|
113
|
+
process.removeListener(signal, handler);
|
|
114
|
+
});
|
|
115
|
+
this.signalHandlers.clear();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Starts the primary process
|
|
119
|
+
*/
|
|
120
|
+
async startPrimary() {
|
|
121
|
+
logger.info(`Primary process (pid: ${process.pid}) starting with ${this.options.numWorkers} workers`);
|
|
122
|
+
// Execute primary initialization function, any error will stop the cluster from starting
|
|
123
|
+
await this.options.primaryFn();
|
|
124
|
+
// Set up cluster event handlers
|
|
125
|
+
this.setupClusterEventHandlers();
|
|
126
|
+
// Spawn initial workers
|
|
127
|
+
for (let i = 0; i < this.options.numWorkers; i += 1) {
|
|
128
|
+
const workerId = i + 1; // Worker IDs start from 1
|
|
129
|
+
this.spawnWorker(workerId);
|
|
130
|
+
}
|
|
131
|
+
// Start health monitoring
|
|
132
|
+
this.startHealthMonitoring();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Starts a worker process
|
|
136
|
+
*/
|
|
137
|
+
async startWorker() {
|
|
138
|
+
logger.info(`Worker ${this.getCurrentWorkerId()} (pid: ${process.pid}) starting`);
|
|
139
|
+
// Set up IPC message handlers
|
|
140
|
+
this.setupWorkerMessageHandlers();
|
|
141
|
+
// Execute worker initialization function, any error will be propagated
|
|
142
|
+
await this.options.workerFn();
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Sets up cluster event handlers for the primary process
|
|
146
|
+
*/
|
|
147
|
+
setupClusterEventHandlers() {
|
|
148
|
+
this.options.cluster.on('exit', (worker, code, signal) => {
|
|
149
|
+
this.handleWorkerExit(worker, code, signal);
|
|
150
|
+
});
|
|
151
|
+
this.options.cluster.on('online', (worker) => {
|
|
152
|
+
logger.info(`Worker ${this.getWorkerId(worker)} (pid: ${worker.process.pid}) is online`);
|
|
153
|
+
this.emit('worker:started', worker);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Sets up IPC message handlers for worker processes
|
|
158
|
+
*/
|
|
159
|
+
setupWorkerMessageHandlers() {
|
|
160
|
+
process.on('message', (message) => {
|
|
161
|
+
switch (message.type) {
|
|
162
|
+
case 'ping':
|
|
163
|
+
this.handleWorkerPing(message);
|
|
164
|
+
break;
|
|
165
|
+
case 'shutdown':
|
|
166
|
+
this.shutdown(message.signal);
|
|
167
|
+
break;
|
|
168
|
+
default:
|
|
169
|
+
logger.warn(`ignoring unknown message type in worker ${process.pid}: ${message.type}`);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Spawns a new worker and sets up its state
|
|
176
|
+
*/
|
|
177
|
+
spawnWorker(id) {
|
|
178
|
+
const worker = this.options.cluster.fork({
|
|
179
|
+
WORKER_ID: id,
|
|
180
|
+
});
|
|
181
|
+
const workerState = {
|
|
182
|
+
id,
|
|
183
|
+
worker,
|
|
184
|
+
restartCount: 0,
|
|
185
|
+
lastPing: Date.now(),
|
|
186
|
+
pendingPing: false,
|
|
187
|
+
isShuttingDown: false,
|
|
188
|
+
};
|
|
189
|
+
this.workers.set(worker.id, workerState);
|
|
190
|
+
// Set up worker message handler
|
|
191
|
+
worker.on('message', (message) => {
|
|
192
|
+
this.handleWorkerMessage(worker, message);
|
|
193
|
+
});
|
|
194
|
+
return worker;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Handles messages from workers
|
|
198
|
+
*/
|
|
199
|
+
handleWorkerMessage(worker, message) {
|
|
200
|
+
const workerState = this.workers.get(worker.id);
|
|
201
|
+
if (!workerState)
|
|
202
|
+
return;
|
|
203
|
+
switch (message.type) {
|
|
204
|
+
case 'pong':
|
|
205
|
+
workerState.lastPing = Date.now();
|
|
206
|
+
workerState.pendingPing = false;
|
|
207
|
+
break;
|
|
208
|
+
default:
|
|
209
|
+
logger.warn(`Received unknown message type from worker ${this.getWorkerId(worker)} (pid: ${worker.process.pid}): ${message.type}`);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Handles ping messages in worker processes
|
|
215
|
+
*/
|
|
216
|
+
handleWorkerPing(message) {
|
|
217
|
+
const pongMessage = {
|
|
218
|
+
type: 'pong',
|
|
219
|
+
timestamp: message.timestamp,
|
|
220
|
+
};
|
|
221
|
+
if (process.send) {
|
|
222
|
+
process.send(pongMessage);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Starts health monitoring for all workers
|
|
227
|
+
*/
|
|
228
|
+
startHealthMonitoring() {
|
|
229
|
+
this.healthCheckInterval = setInterval(() => {
|
|
230
|
+
this.performHealthCheck();
|
|
231
|
+
}, this.options.pingFrequency);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Stops health monitoring
|
|
235
|
+
*/
|
|
236
|
+
stopHealthMonitoring() {
|
|
237
|
+
if (this.healthCheckInterval) {
|
|
238
|
+
clearInterval(this.healthCheckInterval);
|
|
239
|
+
this.healthCheckInterval = null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Performs health check on all workers
|
|
244
|
+
*/
|
|
245
|
+
performHealthCheck() {
|
|
246
|
+
if (this.isShuttingDown)
|
|
247
|
+
return;
|
|
248
|
+
Array.from(this.workers.values())
|
|
249
|
+
.filter((workerState) => !workerState.isShuttingDown)
|
|
250
|
+
.forEach((workerState) => {
|
|
251
|
+
const timeSinceLastPing = Date.now() - workerState.lastPing;
|
|
252
|
+
if (workerState.pendingPing && timeSinceLastPing > this.options.pingTimeout) {
|
|
253
|
+
// Worker is stuck, handle it
|
|
254
|
+
this.handleStuckWorker(workerState);
|
|
255
|
+
}
|
|
256
|
+
else if (!workerState.pendingPing) {
|
|
257
|
+
// Send ping to worker
|
|
258
|
+
this.sendPingToWorker(workerState);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Sends a ping message to a worker
|
|
264
|
+
*/
|
|
265
|
+
sendPingToWorker(workerState) {
|
|
266
|
+
const pingMessage = {
|
|
267
|
+
type: 'ping',
|
|
268
|
+
timestamp: Date.now(),
|
|
269
|
+
};
|
|
270
|
+
workerState.pendingPing = true;
|
|
271
|
+
try {
|
|
272
|
+
workerState.worker.send(pingMessage);
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
logger.error(`Failed to send ping to worker ${workerState.id} (pid: ${workerState.worker.process.pid}): ${error instanceof Error ? error.message : String(error)}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Handles a stuck worker
|
|
280
|
+
*/
|
|
281
|
+
handleStuckWorker(workerState) {
|
|
282
|
+
logger.error(`Worker ${workerState.id} (pid: ${workerState.worker.process.pid}) is stuck, killing it`);
|
|
283
|
+
this.emit('worker:stuck', workerState.worker);
|
|
284
|
+
// Remove worker state
|
|
285
|
+
this.workers.delete(workerState.worker.id);
|
|
286
|
+
// Kill the worker
|
|
287
|
+
workerState.worker.kill('SIGKILL');
|
|
288
|
+
// Determine if we should spawn a replacement
|
|
289
|
+
const shouldSpawn = this.options.stuckWorkerRespawnFunc(workerState.worker);
|
|
290
|
+
if (shouldSpawn && !this.isShuttingDown) {
|
|
291
|
+
logger.info(`Spawning replacement worker for stuck worker ${workerState.id} (pid: ${workerState.worker.process.pid})`);
|
|
292
|
+
const { restartCount } = workerState; // Preserve restart count
|
|
293
|
+
const newWorker = this.spawnWorker(workerState.id);
|
|
294
|
+
const newWorkerState = this.workers.get(newWorker.id);
|
|
295
|
+
if (newWorkerState) {
|
|
296
|
+
newWorkerState.restartCount = restartCount;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
logger.error(`Triggering cluster shutdown due to stuck worker ${workerState.id} (pid: ${workerState.worker.process.pid})`);
|
|
301
|
+
this.shutdown('STUCK_WORKER');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Handles worker exit events
|
|
306
|
+
*/
|
|
307
|
+
handleWorkerExit(worker, code, signal) {
|
|
308
|
+
logger.info(`Worker ${this.getWorkerId(worker)} (pid: ${worker.process.pid}) died with code ${code} and signal ${signal}`);
|
|
309
|
+
this.emit('worker:died', worker, code, signal);
|
|
310
|
+
const workerState = this.workers.get(worker.id);
|
|
311
|
+
if (!workerState)
|
|
312
|
+
return;
|
|
313
|
+
this.workers.delete(worker.id);
|
|
314
|
+
// If we're shutting down or worker was killed intentionally, don't restart
|
|
315
|
+
if (this.isShuttingDown || workerState.isShuttingDown) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// Handle unexpected exit
|
|
319
|
+
this.handleUnexpectedWorkerExit(workerState);
|
|
320
|
+
}
|
|
321
|
+
getWorkerId(worker) {
|
|
322
|
+
return this.workers.get(worker.id)?.id ?? worker.id;
|
|
323
|
+
}
|
|
324
|
+
getCurrentWorkerId() {
|
|
325
|
+
const envWorkerId = process.env.WORKER_ID !== undefined ? Number(process.env.WORKER_ID) : undefined;
|
|
326
|
+
return envWorkerId ?? this.options.cluster.worker?.id ?? -1;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Handles unexpected worker exits with restart logic
|
|
330
|
+
*/
|
|
331
|
+
handleUnexpectedWorkerExit(workerState) {
|
|
332
|
+
const restartCount = workerState.restartCount + 1;
|
|
333
|
+
if (restartCount <= this.options.restartMaxTimes) {
|
|
334
|
+
logger.error(`Restarting worker ${workerState.id} (pid: ${workerState.worker.process.pid}) (attempt ${restartCount}/${this.options.restartMaxTimes})`);
|
|
335
|
+
const newWorker = this.spawnWorker(workerState.id);
|
|
336
|
+
const newWorkerState = this.workers.get(newWorker.id);
|
|
337
|
+
if (newWorkerState) {
|
|
338
|
+
newWorkerState.restartCount = restartCount;
|
|
339
|
+
}
|
|
340
|
+
this.emit('worker:restarted', newWorker, workerState.restartCount);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
logger.error(`Restart limit (${this.options.restartMaxTimes}) exceeded for worker ${workerState.id} (pid: ${workerState.worker.process.pid}), shutting down cluster`);
|
|
344
|
+
this.emit('worker:restart-limit-exceeded', workerState.worker, workerState.restartCount);
|
|
345
|
+
this.shutdown('RESTART_LIMIT_EXCEEDED');
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Shuts down the primary process
|
|
350
|
+
*/
|
|
351
|
+
async shutdownPrimary(signal) {
|
|
352
|
+
logger.info(`Primary process (pid: ${process.pid}) shutting down (signal: ${signal ?? 'manual'})`);
|
|
353
|
+
this.stopHealthMonitoring();
|
|
354
|
+
this.removeSignalHandlers();
|
|
355
|
+
// Shutdown all workers
|
|
356
|
+
await this.shutdownAllWorkers(signal);
|
|
357
|
+
// Execute primary shutdown function
|
|
358
|
+
await (0, utils_1.safeExecute)(() => (0, utils_1.timeout)(this.options.primaryShutdownFn(signal), this.options.shutdownTimeout, 'primary shutdown timeout'), 'Error in primary shutdown function');
|
|
359
|
+
logger.info(`Primary process (pid: ${process.pid}) shutdown completed`);
|
|
360
|
+
this.emit('shutdown:completed');
|
|
361
|
+
process.exit(0);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Shuts down all workers gracefully
|
|
365
|
+
*/
|
|
366
|
+
async shutdownAllWorkers(signal) {
|
|
367
|
+
if (this.workers.size === 0)
|
|
368
|
+
return;
|
|
369
|
+
logger.info(`Shutting down ${this.workers.size} workers...`);
|
|
370
|
+
// Mark all workers as shutting down and send shutdown message
|
|
371
|
+
Array.from(this.workers.values()).forEach((workerState) => {
|
|
372
|
+
workerState.isShuttingDown = true;
|
|
373
|
+
// Only send shutdown message if worker is still connected
|
|
374
|
+
if (!workerState.worker.isDead() && workerState.worker.process.connected) {
|
|
375
|
+
const shutdownMessage = {
|
|
376
|
+
type: 'shutdown',
|
|
377
|
+
signal,
|
|
378
|
+
};
|
|
379
|
+
try {
|
|
380
|
+
workerState.worker.send(shutdownMessage);
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
// Worker IPC channel is already closed, which is fine
|
|
384
|
+
logger.warn(`Failed to send shutdown message to worker ${workerState.id} (pid: ${workerState.worker.process.pid}): ${error instanceof Error ? error.message : String(error)}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
// Wait for workers to exit gracefully or timeout
|
|
389
|
+
try {
|
|
390
|
+
await (0, utils_1.timeout)(this.waitForAllWorkersToExit(), this.options.shutdownTimeout, 'Worker shutdown timeout');
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
logger.error('Graceful shutdown for workers timed out, forcing shutdown');
|
|
394
|
+
this.forceKillAllWorkers();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Waits for all workers to exit
|
|
399
|
+
*/
|
|
400
|
+
async waitForAllWorkersToExit() {
|
|
401
|
+
while (this.workers.size > 0) {
|
|
402
|
+
// eslint-disable-next-line no-await-in-loop
|
|
403
|
+
await (0, utils_1.delay)(100);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Force kills all remaining workers
|
|
408
|
+
*/
|
|
409
|
+
forceKillAllWorkers() {
|
|
410
|
+
Array.from(this.workers.values()).forEach((workerState) => {
|
|
411
|
+
logger.error(`Force killing worker ${workerState.id} (pid: ${workerState.worker.process.pid})`);
|
|
412
|
+
workerState.worker.kill('SIGKILL');
|
|
413
|
+
});
|
|
414
|
+
this.workers.clear();
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Shuts down a worker process
|
|
418
|
+
*/
|
|
419
|
+
async shutdownWorker(signal) {
|
|
420
|
+
logger.info(`Worker ${this.getCurrentWorkerId()} (pid: ${process.pid}) shutting down (signal: ${signal ?? 'manual'})`);
|
|
421
|
+
this.removeSignalHandlers();
|
|
422
|
+
// Execute worker shutdown function
|
|
423
|
+
await (0, utils_1.safeExecute)(() => (0, utils_1.timeout)(this.options.workerShutdownFn(signal), this.options.shutdownTimeout, 'worker shutdown timeout'), `Error in worker ${this.getCurrentWorkerId()} (pid: ${process.pid}) shutdown function`);
|
|
424
|
+
logger.info(`Worker ${this.getCurrentWorkerId()} (pid: ${process.pid}) shutdown completed`);
|
|
425
|
+
process.exit(0);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Gets the current number of active workers
|
|
429
|
+
*/
|
|
430
|
+
getWorkerCount() {
|
|
431
|
+
return this.workers.size;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Gets information about all workers
|
|
435
|
+
*/
|
|
436
|
+
getWorkerInfo() {
|
|
437
|
+
return Array.from(this.workers.values()).map((state) => ({
|
|
438
|
+
id: state.id,
|
|
439
|
+
pid: state.worker.process.pid ?? -1,
|
|
440
|
+
restartCount: state.restartCount,
|
|
441
|
+
}));
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Checks if the cluster is currently started
|
|
445
|
+
*/
|
|
446
|
+
isStarted() {
|
|
447
|
+
return this.started;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Checks if the cluster is currently shutting down
|
|
451
|
+
*/
|
|
452
|
+
isShutdown() {
|
|
453
|
+
return this.isShuttingDown;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
exports.ClusterManager = ClusterManager;
|
|
457
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbHVzdGVyL21hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBR0EsbUNBQXNDO0FBQ3RDLGtEQUFvQztBQVVwQyxtQ0FBaUY7QUFFakY7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBYSxjQUFlLFNBQVEscUJBQVk7SUFlOUMsWUFBWSxVQUFpQyxFQUFFO1FBQzdDLEtBQUssRUFBRSxDQUFDO1FBYk8sWUFBTyxHQUFHLElBQUksR0FBRyxFQUF1QixDQUFDO1FBRWxELFlBQU8sR0FBRyxLQUFLLENBQUM7UUFFaEIsbUJBQWMsR0FBRyxLQUFLLENBQUM7UUFFdkIsb0JBQWUsR0FBeUIsSUFBSSxDQUFDO1FBRTdDLHdCQUFtQixHQUEwQixJQUFJLENBQUM7UUFFbEQsbUJBQWMsR0FBRyxJQUFJLEdBQUcsRUFBOEIsQ0FBQztRQUk3RCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUEsaUNBQXlCLEVBQUMsT0FBTyxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxLQUFLLENBQUMsS0FBSztRQUNoQixJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25DLE1BQU0sSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQzVCLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUNELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7T0FFRztJQUNJLFFBQVEsQ0FBQyxNQUFlO1FBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDbEIsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0IsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBQ3pCLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQztRQUM5QixDQUFDO1FBRUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDM0IsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUV0QyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0RCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNyRCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsZUFBZSxDQUFDO0lBQzlCLENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQjtRQUN6QixJQUFJLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUM5QyxNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUU7Z0JBQ25CLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDeEIsQ0FBQyxDQUFDO1lBQ0YsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ3pDLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzlCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ssb0JBQW9CO1FBQzFCLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxFQUFFLEVBQUU7WUFDdEUsT0FBTyxDQUFDLGNBQWMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsY0FBYyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxZQUFZO1FBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQ1QseUJBQXlCLE9BQU8sQ0FBQyxHQUFHLG1CQUFtQixJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsVUFBVSxDQUN6RixDQUFDO1FBRUYseUZBQXlGO1FBQ3pGLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUUvQixnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLHlCQUF5QixFQUFFLENBQUM7UUFFakMsd0JBQXdCO1FBQ3hCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDcEQsTUFBTSxRQUFRLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLDBCQUEwQjtZQUNsRCxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFFRCwwQkFBMEI7UUFDMUIsSUFBSSxDQUFDLHFCQUFxQixFQUFFLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLFdBQVc7UUFDdkIsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxVQUFVLE9BQU8sQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDO1FBRWxGLDhCQUE4QjtRQUM5QixJQUFJLENBQUMsMEJBQTBCLEVBQUUsQ0FBQztRQUVsQyx1RUFBdUU7UUFDdkUsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNLLHlCQUF5QjtRQUMvQixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsTUFBYyxFQUFFLElBQVksRUFBRSxNQUFjLEVBQUUsRUFBRTtZQUMvRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM5QyxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxNQUFjLEVBQUUsRUFBRTtZQUNuRCxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFBVSxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsYUFBYSxDQUFDLENBQUM7WUFDekYsSUFBSSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN0QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLDBCQUEwQjtRQUNoQyxPQUFPLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQW1CLEVBQUUsRUFBRTtZQUM1QyxRQUFRLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztnQkFDckIsS0FBSyxNQUFNO29CQUNULElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDL0IsTUFBTTtnQkFDUixLQUFLLFVBQVU7b0JBQ2IsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7b0JBQzlCLE1BQU07Z0JBQ1I7b0JBQ0UsTUFBTSxDQUFDLElBQUksQ0FBQywyQ0FBMkMsT0FBTyxDQUFDLEdBQUcsS0FBSyxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDdkYsTUFBTTtZQUNWLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLFdBQVcsQ0FBQyxFQUFVO1FBQzVCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztZQUN2QyxTQUFTLEVBQUUsRUFBRTtTQUNkLENBQUMsQ0FBQztRQUNILE1BQU0sV0FBVyxHQUFnQjtZQUMvQixFQUFFO1lBQ0YsTUFBTTtZQUNOLFlBQVksRUFBRSxDQUFDO1lBQ2YsUUFBUSxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDcEIsV0FBVyxFQUFFLEtBQUs7WUFDbEIsY0FBYyxFQUFFLEtBQUs7U0FDdEIsQ0FBQztRQUVGLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFFekMsZ0NBQWdDO1FBQ2hDLE1BQU0sQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLENBQUMsT0FBbUIsRUFBRSxFQUFFO1lBQzNDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDNUMsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxtQkFBbUIsQ0FBQyxNQUFjLEVBQUUsT0FBbUI7UUFDN0QsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxXQUFXO1lBQUUsT0FBTztRQUV6QixRQUFRLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNyQixLQUFLLE1BQU07Z0JBQ1QsV0FBVyxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ2xDLFdBQVcsQ0FBQyxXQUFXLEdBQUcsS0FBSyxDQUFDO2dCQUNoQyxNQUFNO1lBQ1I7Z0JBQ0UsTUFBTSxDQUFDLElBQUksQ0FDVCw2Q0FBNkMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFDbkUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUNqQixNQUFNLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FDckIsQ0FBQztnQkFDRixNQUFNO1FBQ1YsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLGdCQUFnQixDQUFDLE9BQW9CO1FBQzNDLE1BQU0sV0FBVyxHQUFnQjtZQUMvQixJQUFJLEVBQUUsTUFBTTtZQUNaLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztTQUM3QixDQUFDO1FBRUYsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDakIsT0FBTyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0sscUJBQXFCO1FBQzNCLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxXQUFXLENBQUMsR0FBRyxFQUFFO1lBQzFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzVCLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRDs7T0FFRztJQUNLLG9CQUFvQjtRQUMxQixJQUFJLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQzdCLGFBQWEsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUN4QyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDO1FBQ2xDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxrQkFBa0I7UUFDeEIsSUFBSSxJQUFJLENBQUMsY0FBYztZQUFFLE9BQU87UUFFaEMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQzlCLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDO2FBQ3BELE9BQU8sQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ3ZCLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLFdBQVcsQ0FBQyxRQUFRLENBQUM7WUFFNUQsSUFBSSxXQUFXLENBQUMsV0FBVyxJQUFJLGlCQUFpQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUM7Z0JBQzVFLDZCQUE2QjtnQkFDN0IsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ3RDLENBQUM7aUJBQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDcEMsc0JBQXNCO2dCQUN0QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDckMsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVEOztPQUVHO0lBQ0ssZ0JBQWdCLENBQUMsV0FBd0I7UUFDL0MsTUFBTSxXQUFXLEdBQWdCO1lBQy9CLElBQUksRUFBRSxNQUFNO1lBQ1osU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7U0FDdEIsQ0FBQztRQUVGLFdBQVcsQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQy9CLElBQUksQ0FBQztZQUNILFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FDVixpQ0FBaUMsV0FBVyxDQUFDLEVBQUUsVUFDN0MsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FDN0IsTUFBTSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FDL0QsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxpQkFBaUIsQ0FBQyxXQUF3QjtRQUNoRCxNQUFNLENBQUMsS0FBSyxDQUNWLFVBQVUsV0FBVyxDQUFDLEVBQUUsVUFBVSxXQUFXLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLHdCQUF3QixDQUN6RixDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsV0FBVyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTlDLHNCQUFzQjtRQUN0QixJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRTNDLGtCQUFrQjtRQUNsQixXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVuQyw2Q0FBNkM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxzQkFBc0IsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFNUUsSUFBSSxXQUFXLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFDeEMsTUFBTSxDQUFDLElBQUksQ0FDVCxnREFBZ0QsV0FBVyxDQUFDLEVBQUUsVUFBVSxXQUFXLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEdBQUcsQ0FDMUcsQ0FBQztZQUNGLE1BQU0sRUFBRSxZQUFZLEVBQUUsR0FBRyxXQUFXLENBQUMsQ0FBQyx5QkFBeUI7WUFDL0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDbkQsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3RELElBQUksY0FBYyxFQUFFLENBQUM7Z0JBQ25CLGNBQWMsQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO1lBQzdDLENBQUM7UUFDSCxDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sQ0FBQyxLQUFLLENBQ1YsbURBQW1ELFdBQVcsQ0FBQyxFQUFFLFVBQVUsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxHQUFHLENBQzdHLENBQUM7WUFDRixJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2hDLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0IsQ0FBQyxNQUFjLEVBQUUsSUFBbUIsRUFBRSxNQUFxQjtRQUNqRixNQUFNLENBQUMsSUFBSSxDQUNULFVBQVUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsVUFDaEMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUNqQixvQkFBb0IsSUFBSSxlQUFlLE1BQU0sRUFBRSxDQUNoRCxDQUFDO1FBQ0YsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUUvQyxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDaEQsSUFBSSxDQUFDLFdBQVc7WUFBRSxPQUFPO1FBRXpCLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUUvQiwyRUFBMkU7UUFDM0UsSUFBSSxJQUFJLENBQUMsY0FBYyxJQUFJLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN0RCxPQUFPO1FBQ1QsQ0FBQztRQUVELHlCQUF5QjtRQUN6QixJQUFJLENBQUMsMEJBQTBCLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVPLFdBQVcsQ0FBQyxNQUFjO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsSUFBSSxNQUFNLENBQUMsRUFBRSxDQUFDO0lBQ3RELENBQUM7SUFFTyxrQkFBa0I7UUFDeEIsTUFBTSxXQUFXLEdBQ2YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBQ2xGLE9BQU8sV0FBVyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVEOztPQUVHO0lBQ0ssMEJBQTBCLENBQUMsV0FBd0I7UUFDekQsTUFBTSxZQUFZLEdBQUcsV0FBVyxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUM7UUFFbEQsSUFBSSxZQUFZLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUNqRCxNQUFNLENBQUMsS0FBSyxDQUNWLHFCQUFxQixXQUFXLENBQUMsRUFBRSxVQUFVLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsY0FBYyxZQUFZLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLEdBQUcsQ0FDekksQ0FBQztZQUNGLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ25ELE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0RCxJQUFJLGNBQWMsRUFBRSxDQUFDO2dCQUNuQixjQUFjLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztZQUM3QyxDQUFDO1lBQ0QsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxTQUFTLEVBQUUsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3JFLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxDQUFDLEtBQUssQ0FDVixrQkFBa0IsSUFBSSxDQUFDLE9BQU8sQ0FBQyxlQUFlLHlCQUF5QixXQUFXLENBQUMsRUFBRSxVQUFVLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsMEJBQTBCLENBQ3hKLENBQUM7WUFDRixJQUFJLENBQUMsSUFBSSxDQUFDLCtCQUErQixFQUFFLFdBQVcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3pGLElBQUksQ0FBQyxRQUFRLENBQUMsd0JBQXdCLENBQUMsQ0FBQztRQUMxQyxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLGVBQWUsQ0FBQyxNQUFlO1FBQzNDLE1BQU0sQ0FBQyxJQUFJLENBQ1QseUJBQXlCLE9BQU8sQ0FBQyxHQUFHLDRCQUE0QixNQUFNLElBQUksUUFBUSxHQUFHLENBQ3RGLENBQUM7UUFFRixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUU1Qix1QkFBdUI7UUFDdkIsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFdEMsb0NBQW9DO1FBQ3BDLE1BQU0sSUFBQSxtQkFBVyxFQUNmLEdBQUcsRUFBRSxDQUNILElBQUEsZUFBTyxFQUNMLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLEVBQ3RDLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUM1QiwwQkFBMEIsQ0FDM0IsRUFDSCxvQ0FBb0MsQ0FDckMsQ0FBQztRQUVGLE1BQU0sQ0FBQyxJQUFJLENBQUMseUJBQXlCLE9BQU8sQ0FBQyxHQUFHLHNCQUFzQixDQUFDLENBQUM7UUFDeEUsSUFBSSxDQUFDLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssS0FBSyxDQUFDLGtCQUFrQixDQUFDLE1BQWU7UUFDOUMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksS0FBSyxDQUFDO1lBQUUsT0FBTztRQUVwQyxNQUFNLENBQUMsSUFBSSxDQUFDLGlCQUFpQixJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksYUFBYSxDQUFDLENBQUM7UUFFN0QsOERBQThEO1FBQzlELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQ3hELFdBQVcsQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1lBQ2xDLDBEQUEwRDtZQUMxRCxJQUFJLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxXQUFXLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDekUsTUFBTSxlQUFlLEdBQW9CO29CQUN2QyxJQUFJLEVBQUUsVUFBVTtvQkFDaEIsTUFBTTtpQkFDUCxDQUFDO2dCQUNGLElBQUksQ0FBQztvQkFDSCxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztnQkFDM0MsQ0FBQztnQkFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO29CQUNmLHNEQUFzRDtvQkFDdEQsTUFBTSxDQUFDLElBQUksQ0FDVCw2Q0FBNkMsV0FBVyxDQUFDLEVBQUUsVUFDekQsV0FBVyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FDN0IsTUFBTSxLQUFLLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FDL0QsQ0FBQztnQkFDSixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsaURBQWlEO1FBQ2pELElBQUksQ0FBQztZQUNILE1BQU0sSUFBQSxlQUFPLEVBQ1gsSUFBSSxDQUFDLHVCQUF1QixFQUFFLEVBQzlCLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUM1Qix5QkFBeUIsQ0FDMUIsQ0FBQztRQUNKLENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxDQUFDLEtBQUssQ0FBQywyREFBMkQsQ0FBQyxDQUFDO1lBQzFFLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzdCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMsdUJBQXVCO1FBQ25DLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDN0IsNENBQTRDO1lBQzVDLE1BQU0sSUFBQSxhQUFLLEVBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkIsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNLLG1CQUFtQjtRQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRTtZQUN4RCxNQUFNLENBQUMsS0FBSyxDQUNWLHdCQUF3QixXQUFXLENBQUMsRUFBRSxVQUFVLFdBQVcsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsR0FBRyxDQUNsRixDQUFDO1lBQ0YsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNLLEtBQUssQ0FBQyxjQUFjLENBQUMsTUFBZTtRQUMxQyxNQUFNLENBQUMsSUFBSSxDQUNULFVBQVUsSUFBSSxDQUFDLGtCQUFrQixFQUFFLFVBQVUsT0FBTyxDQUFDLEdBQUcsNEJBQ3RELE1BQU0sSUFBSSxRQUNaLEdBQUcsQ0FDSixDQUFDO1FBRUYsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFFNUIsbUNBQW1DO1FBQ25DLE1BQU0sSUFBQSxtQkFBVyxFQUNmLEdBQUcsRUFBRSxDQUNILElBQUEsZUFBTyxFQUNMLElBQUksQ0FBQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEVBQ3JDLElBQUksQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUM1Qix5QkFBeUIsQ0FDMUIsRUFDSCxtQkFBbUIsSUFBSSxDQUFDLGtCQUFrQixFQUFFLFVBQVUsT0FBTyxDQUFDLEdBQUcscUJBQXFCLENBQ3ZGLENBQUM7UUFFRixNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLGtCQUFrQixFQUFFLFVBQVUsT0FBTyxDQUFDLEdBQUcsc0JBQXNCLENBQUMsQ0FBQztRQUM1RixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7T0FFRztJQUNJLGNBQWM7UUFDbkIsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztJQUMzQixDQUFDO0lBRUQ7O09BRUc7SUFDSSxhQUFhO1FBQ2xCLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRTtZQUNaLEdBQUcsRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1lBQ25DLFlBQVksRUFBRSxLQUFLLENBQUMsWUFBWTtTQUNqQyxDQUFDLENBQUMsQ0FBQztJQUNOLENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDdEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ksVUFBVTtRQUNmLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0NBQ0Y7QUE3Z0JELHdDQTZnQkMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBjbGFzcy1tZXRob2RzLXVzZS10aGlzICovXG4vKiBlc2xpbnQtZGlzYWJsZSBuby1wYXJhbS1yZWFzc2lnbiAqL1xuaW1wb3J0IHsgV29ya2VyIH0gZnJvbSAnY2x1c3Rlcic7XG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdldmVudHMnO1xuaW1wb3J0ICogYXMgbG9nZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQge1xuICBDbHVzdGVyTWFuYWdlck9wdGlvbnMsXG4gIENsdXN0ZXJNYW5hZ2VyRXZlbnRzLFxuICBXb3JrZXJTdGF0ZSxcbiAgSVBDTWVzc2FnZSxcbiAgUGluZ01lc3NhZ2UsXG4gIFBvbmdNZXNzYWdlLFxuICBTaHV0ZG93bk1lc3NhZ2UsXG59IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgZGVsYXksIHRpbWVvdXQsIHNhZmVFeGVjdXRlLCB2YWxpZGF0ZUFuZERlZmF1bHRPcHRpb25zIH0gZnJvbSAnLi91dGlscyc7XG5cbi8qKlxuICogQ2x1c3Rlck1hbmFnZXIgLSBBIGNsdXN0ZXIgbGlmZWN5Y2xlIG1hbmFnZW1lbnQgc3lzdGVtXG4gKlxuICogVGhlIG1hbmFnZXIgc3VwcG9ydHMgdGhlIGZvbGxvd2luZyBmZWF0dXJlczpcbiAqIC0gR3JhY2VmdWwgc2h1dGRvd24gd2l0aCBjb25maWd1cmFibGUgdGltZW91dFxuICogLSBXb3JrZXIgaGVhbHRoIG1vbml0b3Jpbmcgd2l0aCBwaW5nL3BvbmcgbWVjaGFuaXNtXG4gKiAtIEF1dG9tYXRpYyB3b3JrZXIgcmVzdGFydCB3aXRoIGNvbmZpZ3VyYWJsZSBsaW1pdHNcbiAqIC0gU2lnbmFsIGhhbmRsaW5nIGZvciBzaHV0ZG93biB0cmlnZ2Vyc1xuICogLSBGbGV4aWJsZSBwcmltYXJ5IGFuZCB3b3JrZXIgZnVuY3Rpb24gaGFuZGxlcnNcbiAqL1xuZXhwb3J0IGNsYXNzIENsdXN0ZXJNYW5hZ2VyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zOiBSZXF1aXJlZDxDbHVzdGVyTWFuYWdlck9wdGlvbnM+O1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgd29ya2VycyA9IG5ldyBNYXA8bnVtYmVyLCBXb3JrZXJTdGF0ZT4oKTtcblxuICBwcml2YXRlIHN0YXJ0ZWQgPSBmYWxzZTtcblxuICBwcml2YXRlIGlzU2h1dHRpbmdEb3duID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSBzaHV0ZG93blByb21pc2U6IFByb21pc2U8dm9pZD4gfCBudWxsID0gbnVsbDtcblxuICBwcml2YXRlIGhlYWx0aENoZWNrSW50ZXJ2YWw6IE5vZGVKUy5UaW1lb3V0IHwgbnVsbCA9IG51bGw7XG5cbiAgcHJpdmF0ZSBzaWduYWxIYW5kbGVycyA9IG5ldyBNYXA8Tm9kZUpTLlNpZ25hbHMsICgpID0+IHZvaWQ+KCk7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogQ2x1c3Rlck1hbmFnZXJPcHRpb25zID0ge30pIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMub3B0aW9ucyA9IHZhbGlkYXRlQW5kRGVmYXVsdE9wdGlvbnMob3B0aW9ucyk7XG4gICAgdGhpcy5zZXR1cFNpZ25hbEhhbmRsZXJzKCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnRzIHRoZSBjbHVzdGVyIG1hbmFnZXJcbiAgICogSW4gcHJpbWFyeSBwcm9jZXNzOiBzdGFydHMgd29ya2VycyBhbmQgaGVhbHRoIG1vbml0b3JpbmdcbiAgICogSW4gd29ya2VyIHByb2Nlc3M6IGV4ZWN1dGVzIHdvcmtlciBmdW5jdGlvblxuICAgKi9cbiAgcHVibGljIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLm9wdGlvbnMuY2x1c3Rlci5pc1ByaW1hcnkpIHtcbiAgICAgIGF3YWl0IHRoaXMuc3RhcnRQcmltYXJ5KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IHRoaXMuc3RhcnRXb3JrZXIoKTtcbiAgICB9XG4gICAgdGhpcy5zdGFydGVkID0gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWF0ZXMgZ3JhY2VmdWwgc2h1dGRvd24gb2YgdGhlIGNsdXN0ZXJcbiAgICovXG4gIHB1YmxpYyBzaHV0ZG93bihzaWduYWw/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuc3RhcnRlZCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnNodXRkb3duUHJvbWlzZSkge1xuICAgICAgcmV0dXJuIHRoaXMuc2h1dGRvd25Qcm9taXNlO1xuICAgIH1cblxuICAgIHRoaXMuaXNTaHV0dGluZ0Rvd24gPSB0cnVlO1xuICAgIHRoaXMuZW1pdCgnc2h1dGRvd246c3RhcnRlZCcsIHNpZ25hbCk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLmNsdXN0ZXIuaXNQcmltYXJ5KSB7XG4gICAgICB0aGlzLnNodXRkb3duUHJvbWlzZSA9IHRoaXMuc2h1dGRvd25QcmltYXJ5KHNpZ25hbCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2h1dGRvd25Qcm9taXNlID0gdGhpcy5zaHV0ZG93bldvcmtlcihzaWduYWwpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnNodXRkb3duUHJvbWlzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHVwIHNpZ25hbCBoYW5kbGVycyBmb3IgZ3JhY2VmdWwgc2h1dGRvd25cbiAgICovXG4gIHByaXZhdGUgc2V0dXBTaWduYWxIYW5kbGVycygpOiB2b2lkIHtcbiAgICB0aGlzLm9wdGlvbnMuc2h1dGRvd25TaWduYWxzLmZvckVhY2goKHNpZ25hbCkgPT4ge1xuICAgICAgY29uc3QgaGFuZGxlciA9ICgpID0+IHtcbiAgICAgICAgdGhpcy5zaHV0ZG93bihzaWduYWwpO1xuICAgICAgfTtcbiAgICAgIHRoaXMuc2lnbmFsSGFuZGxlcnMuc2V0KHNpZ25hbCwgaGFuZGxlcik7XG4gICAgICBwcm9jZXNzLm9uKHNpZ25hbCwgaGFuZGxlcik7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBzaWduYWwgaGFuZGxlcnNcbiAgICovXG4gIHByaXZhdGUgcmVtb3ZlU2lnbmFsSGFuZGxlcnMoKTogdm9pZCB7XG4gICAgQXJyYXkuZnJvbSh0aGlzLnNpZ25hbEhhbmRsZXJzLmVudHJpZXMoKSkuZm9yRWFjaCgoW3NpZ25hbCwgaGFuZGxlcl0pID0+IHtcbiAgICAgIHByb2Nlc3MucmVtb3ZlTGlzdGVuZXIoc2lnbmFsLCBoYW5kbGVyKTtcbiAgICB9KTtcbiAgICB0aGlzLnNpZ25hbEhhbmRsZXJzLmNsZWFyKCk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnRzIHRoZSBwcmltYXJ5IHByb2Nlc3NcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgc3RhcnRQcmltYXJ5KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZ2dlci5pbmZvKFxuICAgICAgYFByaW1hcnkgcHJvY2VzcyAocGlkOiAke3Byb2Nlc3MucGlkfSkgc3RhcnRpbmcgd2l0aCAke3RoaXMub3B0aW9ucy5udW1Xb3JrZXJzfSB3b3JrZXJzYCxcbiAgICApO1xuXG4gICAgLy8gRXhlY3V0ZSBwcmltYXJ5IGluaXRpYWxpemF0aW9uIGZ1bmN0aW9uLCBhbnkgZXJyb3Igd2lsbCBzdG9wIHRoZSBjbHVzdGVyIGZyb20gc3RhcnRpbmdcbiAgICBhd2FpdCB0aGlzLm9wdGlvbnMucHJpbWFyeUZuKCk7XG5cbiAgICAvLyBTZXQgdXAgY2x1c3RlciBldmVudCBoYW5kbGVyc1xuICAgIHRoaXMuc2V0dXBDbHVzdGVyRXZlbnRIYW5kbGVycygpO1xuXG4gICAgLy8gU3Bhd24gaW5pdGlhbCB3b3JrZXJzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLm9wdGlvbnMubnVtV29ya2VyczsgaSArPSAxKSB7XG4gICAgICBjb25zdCB3b3JrZXJJZCA9IGkgKyAxOyAvLyBXb3JrZXIgSURzIHN0YXJ0IGZyb20gMVxuICAgICAgdGhpcy5zcGF3bldvcmtlcih3b3JrZXJJZCk7XG4gICAgfVxuXG4gICAgLy8gU3RhcnQgaGVhbHRoIG1vbml0b3JpbmdcbiAgICB0aGlzLnN0YXJ0SGVhbHRoTW9uaXRvcmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0cyBhIHdvcmtlciBwcm9jZXNzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHN0YXJ0V29ya2VyKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZ2dlci5pbmZvKGBXb3JrZXIgJHt0aGlzLmdldEN1cnJlbnRXb3JrZXJJZCgpfSAocGlkOiAke3Byb2Nlc3MucGlkfSkgc3RhcnRpbmdgKTtcblxuICAgIC8vIFNldCB1cCBJUEMgbWVzc2FnZSBoYW5kbGVyc1xuICAgIHRoaXMuc2V0dXBXb3JrZXJNZXNzYWdlSGFuZGxlcnMoKTtcblxuICAgIC8vIEV4ZWN1dGUgd29ya2VyIGluaXRpYWxpemF0aW9uIGZ1bmN0aW9uLCBhbnkgZXJyb3Igd2lsbCBiZSBwcm9wYWdhdGVkXG4gICAgYXdhaXQgdGhpcy5vcHRpb25zLndvcmtlckZuKCk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB1cCBjbHVzdGVyIGV2ZW50IGhhbmRsZXJzIGZvciB0aGUgcHJpbWFyeSBwcm9jZXNzXG4gICAqL1xuICBwcml2YXRlIHNldHVwQ2x1c3RlckV2ZW50SGFuZGxlcnMoKTogdm9pZCB7XG4gICAgdGhpcy5vcHRpb25zLmNsdXN0ZXIub24oJ2V4aXQnLCAod29ya2VyOiBXb3JrZXIsIGNvZGU6IG51bWJlciwgc2lnbmFsOiBzdHJpbmcpID0+IHtcbiAgICAgIHRoaXMuaGFuZGxlV29ya2VyRXhpdCh3b3JrZXIsIGNvZGUsIHNpZ25hbCk7XG4gICAgfSk7XG5cbiAgICB0aGlzLm9wdGlvbnMuY2x1c3Rlci5vbignb25saW5lJywgKHdvcmtlcjogV29ya2VyKSA9PiB7XG4gICAgICBsb2dnZXIuaW5mbyhgV29ya2VyICR7dGhpcy5nZXRXb3JrZXJJZCh3b3JrZXIpfSAocGlkOiAke3dvcmtlci5wcm9jZXNzLnBpZH0pIGlzIG9ubGluZWApO1xuICAgICAgdGhpcy5lbWl0KCd3b3JrZXI6c3RhcnRlZCcsIHdvcmtlcik7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB1cCBJUEMgbWVzc2FnZSBoYW5kbGVycyBmb3Igd29ya2VyIHByb2Nlc3Nlc1xuICAgKi9cbiAgcHJpdmF0ZSBzZXR1cFdvcmtlck1lc3NhZ2VIYW5kbGVycygpOiB2b2lkIHtcbiAgICBwcm9jZXNzLm9uKCdtZXNzYWdlJywgKG1lc3NhZ2U6IElQQ01lc3NhZ2UpID0+IHtcbiAgICAgIHN3aXRjaCAobWVzc2FnZS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ3BpbmcnOlxuICAgICAgICAgIHRoaXMuaGFuZGxlV29ya2VyUGluZyhtZXNzYWdlKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnc2h1dGRvd24nOlxuICAgICAgICAgIHRoaXMuc2h1dGRvd24obWVzc2FnZS5zaWduYWwpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGxvZ2dlci53YXJuKGBpZ25vcmluZyB1bmtub3duIG1lc3NhZ2UgdHlwZSBpbiB3b3JrZXIgJHtwcm9jZXNzLnBpZH06ICR7bWVzc2FnZS50eXBlfWApO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNwYXducyBhIG5ldyB3b3JrZXIgYW5kIHNldHMgdXAgaXRzIHN0YXRlXG4gICAqL1xuICBwcml2YXRlIHNwYXduV29ya2VyKGlkOiBudW1iZXIpOiBXb3JrZXIge1xuICAgIGNvbnN0IHdvcmtlciA9IHRoaXMub3B0aW9ucy5jbHVzdGVyLmZvcmsoe1xuICAgICAgV09SS0VSX0lEOiBpZCxcbiAgICB9KTtcbiAgICBjb25zdCB3b3JrZXJTdGF0ZTogV29ya2VyU3RhdGUgPSB7XG4gICAgICBpZCxcbiAgICAgIHdvcmtlcixcbiAgICAgIHJlc3RhcnRDb3VudDogMCxcbiAgICAgIGxhc3RQaW5nOiBEYXRlLm5vdygpLFxuICAgICAgcGVuZGluZ1Bpbmc6IGZhbHNlLFxuICAgICAgaXNTaHV0dGluZ0Rvd246IGZhbHNlLFxuICAgIH07XG5cbiAgICB0aGlzLndvcmtlcnMuc2V0KHdvcmtlci5pZCwgd29ya2VyU3RhdGUpO1xuXG4gICAgLy8gU2V0IHVwIHdvcmtlciBtZXNzYWdlIGhhbmRsZXJcbiAgICB3b3JrZXIub24oJ21lc3NhZ2UnLCAobWVzc2FnZTogSVBDTWVzc2FnZSkgPT4ge1xuICAgICAgdGhpcy5oYW5kbGVXb3JrZXJNZXNzYWdlKHdvcmtlciwgbWVzc2FnZSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gd29ya2VyO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgbWVzc2FnZXMgZnJvbSB3b3JrZXJzXG4gICAqL1xuICBwcml2YXRlIGhhbmRsZVdvcmtlck1lc3NhZ2Uod29ya2VyOiBXb3JrZXIsIG1lc3NhZ2U6IElQQ01lc3NhZ2UpOiB2b2lkIHtcbiAgICBjb25zdCB3b3JrZXJTdGF0ZSA9IHRoaXMud29ya2Vycy5nZXQod29ya2VyLmlkKTtcbiAgICBpZiAoIXdvcmtlclN0YXRlKSByZXR1cm47XG5cbiAgICBzd2l0Y2ggKG1lc3NhZ2UudHlwZSkge1xuICAgICAgY2FzZSAncG9uZyc6XG4gICAgICAgIHdvcmtlclN0YXRlLmxhc3RQaW5nID0gRGF0ZS5ub3coKTtcbiAgICAgICAgd29ya2VyU3RhdGUucGVuZGluZ1BpbmcgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICBgUmVjZWl2ZWQgdW5rbm93biBtZXNzYWdlIHR5cGUgZnJvbSB3b3JrZXIgJHt0aGlzLmdldFdvcmtlcklkKHdvcmtlcil9IChwaWQ6ICR7XG4gICAgICAgICAgICB3b3JrZXIucHJvY2Vzcy5waWRcbiAgICAgICAgICB9KTogJHttZXNzYWdlLnR5cGV9YCxcbiAgICAgICAgKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgcGluZyBtZXNzYWdlcyBpbiB3b3JrZXIgcHJvY2Vzc2VzXG4gICAqL1xuICBwcml2YXRlIGhhbmRsZVdvcmtlclBpbmcobWVzc2FnZTogUGluZ01lc3NhZ2UpOiB2b2lkIHtcbiAgICBjb25zdCBwb25nTWVzc2FnZTogUG9uZ01lc3NhZ2UgPSB7XG4gICAgICB0eXBlOiAncG9uZycsXG4gICAgICB0aW1lc3RhbXA6IG1lc3NhZ2UudGltZXN0YW1wLFxuICAgIH07XG5cbiAgICBpZiAocHJvY2Vzcy5zZW5kKSB7XG4gICAgICBwcm9jZXNzLnNlbmQocG9uZ01lc3NhZ2UpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydHMgaGVhbHRoIG1vbml0b3JpbmcgZm9yIGFsbCB3b3JrZXJzXG4gICAqL1xuICBwcml2YXRlIHN0YXJ0SGVhbHRoTW9uaXRvcmluZygpOiB2b2lkIHtcbiAgICB0aGlzLmhlYWx0aENoZWNrSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICB0aGlzLnBlcmZvcm1IZWFsdGhDaGVjaygpO1xuICAgIH0sIHRoaXMub3B0aW9ucy5waW5nRnJlcXVlbmN5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyBoZWFsdGggbW9uaXRvcmluZ1xuICAgKi9cbiAgcHJpdmF0ZSBzdG9wSGVhbHRoTW9uaXRvcmluZygpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5oZWFsdGhDaGVja0ludGVydmFsKSB7XG4gICAgICBjbGVhckludGVydmFsKHRoaXMuaGVhbHRoQ2hlY2tJbnRlcnZhbCk7XG4gICAgICB0aGlzLmhlYWx0aENoZWNrSW50ZXJ2YWwgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtcyBoZWFsdGggY2hlY2sgb24gYWxsIHdvcmtlcnNcbiAgICovXG4gIHByaXZhdGUgcGVyZm9ybUhlYWx0aENoZWNrKCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzU2h1dHRpbmdEb3duKSByZXR1cm47XG5cbiAgICBBcnJheS5mcm9tKHRoaXMud29ya2Vycy52YWx1ZXMoKSlcbiAgICAgIC5maWx0ZXIoKHdvcmtlclN0YXRlKSA9PiAhd29ya2VyU3RhdGUuaXNTaHV0dGluZ0Rvd24pXG4gICAgICAuZm9yRWFjaCgod29ya2VyU3RhdGUpID0+IHtcbiAgICAgICAgY29uc3QgdGltZVNpbmNlTGFzdFBpbmcgPSBEYXRlLm5vdygpIC0gd29ya2VyU3RhdGUubGFzdFBpbmc7XG5cbiAgICAgICAgaWYgKHdvcmtlclN0YXRlLnBlbmRpbmdQaW5nICYmIHRpbWVTaW5jZUxhc3RQaW5nID4gdGhpcy5vcHRpb25zLnBpbmdUaW1lb3V0KSB7XG4gICAgICAgICAgLy8gV29ya2VyIGlzIHN0dWNrLCBoYW5kbGUgaXRcbiAgICAgICAgICB0aGlzLmhhbmRsZVN0dWNrV29ya2VyKHdvcmtlclN0YXRlKTtcbiAgICAgICAgfSBlbHNlIGlmICghd29ya2VyU3RhdGUucGVuZGluZ1BpbmcpIHtcbiAgICAgICAgICAvLyBTZW5kIHBpbmcgdG8gd29ya2VyXG4gICAgICAgICAgdGhpcy5zZW5kUGluZ1RvV29ya2VyKHdvcmtlclN0YXRlKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU2VuZHMgYSBwaW5nIG1lc3NhZ2UgdG8gYSB3b3JrZXJcbiAgICovXG4gIHByaXZhdGUgc2VuZFBpbmdUb1dvcmtlcih3b3JrZXJTdGF0ZTogV29ya2VyU3RhdGUpOiB2b2lkIHtcbiAgICBjb25zdCBwaW5nTWVzc2FnZTogUGluZ01lc3NhZ2UgPSB7XG4gICAgICB0eXBlOiAncGluZycsXG4gICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgfTtcblxuICAgIHdvcmtlclN0YXRlLnBlbmRpbmdQaW5nID0gdHJ1ZTtcbiAgICB0cnkge1xuICAgICAgd29ya2VyU3RhdGUud29ya2VyLnNlbmQocGluZ01lc3NhZ2UpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgIGBGYWlsZWQgdG8gc2VuZCBwaW5nIHRvIHdvcmtlciAke3dvcmtlclN0YXRlLmlkfSAocGlkOiAke1xuICAgICAgICAgIHdvcmtlclN0YXRlLndvcmtlci5wcm9jZXNzLnBpZFxuICAgICAgICB9KTogJHtlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcil9YCxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEhhbmRsZXMgYSBzdHVjayB3b3JrZXJcbiAgICovXG4gIHByaXZhdGUgaGFuZGxlU3R1Y2tXb3JrZXIod29ya2VyU3RhdGU6IFdvcmtlclN0YXRlKTogdm9pZCB7XG4gICAgbG9nZ2VyLmVycm9yKFxuICAgICAgYFdvcmtlciAke3dvcmtlclN0YXRlLmlkfSAocGlkOiAke3dvcmtlclN0YXRlLndvcmtlci5wcm9jZXNzLnBpZH0pIGlzIHN0dWNrLCBraWxsaW5nIGl0YCxcbiAgICApO1xuICAgIHRoaXMuZW1pdCgnd29ya2VyOnN0dWNrJywgd29ya2VyU3RhdGUud29ya2VyKTtcblxuICAgIC8vIFJlbW92ZSB3b3JrZXIgc3RhdGVcbiAgICB0aGlzLndvcmtlcnMuZGVsZXRlKHdvcmtlclN0YXRlLndvcmtlci5pZCk7XG5cbiAgICAvLyBLaWxsIHRoZSB3b3JrZXJcbiAgICB3b3JrZXJTdGF0ZS53b3JrZXIua2lsbCgnU0lHS0lMTCcpO1xuXG4gICAgLy8gRGV0ZXJtaW5lIGlmIHdlIHNob3VsZCBzcGF3biBhIHJlcGxhY2VtZW50XG4gICAgY29uc3Qgc2hvdWxkU3Bhd24gPSB0aGlzLm9wdGlvbnMuc3R1Y2tXb3JrZXJSZXNwYXduRnVuYyh3b3JrZXJTdGF0ZS53b3JrZXIpO1xuXG4gICAgaWYgKHNob3VsZFNwYXduICYmICF0aGlzLmlzU2h1dHRpbmdEb3duKSB7XG4gICAgICBsb2dnZXIuaW5mbyhcbiAgICAgICAgYFNwYXduaW5nIHJlcGxhY2VtZW50IHdvcmtlciBmb3Igc3R1Y2sgd29ya2VyICR7d29ya2VyU3RhdGUuaWR9IChwaWQ6ICR7d29ya2VyU3RhdGUud29ya2VyLnByb2Nlc3MucGlkfSlgLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHsgcmVzdGFydENvdW50IH0gPSB3b3JrZXJTdGF0ZTsgLy8gUHJlc2VydmUgcmVzdGFydCBjb3VudFxuICAgICAgY29uc3QgbmV3V29ya2VyID0gdGhpcy5zcGF3bldvcmtlcih3b3JrZXJTdGF0ZS5pZCk7XG4gICAgICBjb25zdCBuZXdXb3JrZXJTdGF0ZSA9IHRoaXMud29ya2Vycy5nZXQobmV3V29ya2VyLmlkKTtcbiAgICAgIGlmIChuZXdXb3JrZXJTdGF0ZSkge1xuICAgICAgICBuZXdXb3JrZXJTdGF0ZS5yZXN0YXJ0Q291bnQgPSByZXN0YXJ0Q291bnQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgYFRyaWdnZXJpbmcgY2x1c3RlciBzaHV0ZG93biBkdWUgdG8gc3R1Y2sgd29ya2VyICR7d29ya2VyU3RhdGUuaWR9IChwaWQ6ICR7d29ya2VyU3RhdGUud29ya2VyLnByb2Nlc3MucGlkfSlgLFxuICAgICAgKTtcbiAgICAgIHRoaXMuc2h1dGRvd24oJ1NUVUNLX1dPUktFUicpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBIYW5kbGVzIHdvcmtlciBleGl0IGV2ZW50c1xuICAgKi9cbiAgcHJpdmF0ZSBoYW5kbGVXb3JrZXJFeGl0KHdvcmtlcjogV29ya2VyLCBjb2RlOiBudW1iZXIgfCBudWxsLCBzaWduYWw6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbyhcbiAgICAgIGBXb3JrZXIgJHt0aGlzLmdldFdvcmtlcklkKHdvcmtlcil9IChwaWQ6ICR7XG4gICAgICAgIHdvcmtlci5wcm9jZXNzLnBpZFxuICAgICAgfSkgZGllZCB3aXRoIGNvZGUgJHtjb2RlfSBhbmQgc2lnbmFsICR7c2lnbmFsfWAsXG4gICAgKTtcbiAgICB0aGlzLmVtaXQoJ3dvcmtlcjpkaWVkJywgd29ya2VyLCBjb2RlLCBzaWduYWwpO1xuXG4gICAgY29uc3Qgd29ya2VyU3RhdGUgPSB0aGlzLndvcmtlcnMuZ2V0KHdvcmtlci5pZCk7XG4gICAgaWYgKCF3b3JrZXJTdGF0ZSkgcmV0dXJuO1xuXG4gICAgdGhpcy53b3JrZXJzLmRlbGV0ZSh3b3JrZXIuaWQpO1xuXG4gICAgLy8gSWYgd2UncmUgc2h1dHRpbmcgZG93biBvciB3b3JrZXIgd2FzIGtpbGxlZCBpbnRlbnRpb25hbGx5LCBkb24ndCByZXN0YXJ0XG4gICAgaWYgKHRoaXMuaXNTaHV0dGluZ0Rvd24gfHwgd29ya2VyU3RhdGUuaXNTaHV0dGluZ0Rvd24pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgdW5leHBlY3RlZCBleGl0XG4gICAgdGhpcy5oYW5kbGVVbmV4cGVjdGVkV29ya2VyRXhpdCh3b3JrZXJTdGF0ZSk7XG4gIH1cblxuICBwcml2YXRlIGdldFdvcmtlcklkKHdvcmtlcjogV29ya2VyKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy53b3JrZXJzLmdldCh3b3JrZXIuaWQpPy5pZCA/PyB3b3JrZXIuaWQ7XG4gIH1cblxuICBwcml2YXRlIGdldEN1cnJlbnRXb3JrZXJJZCgpOiBudW1iZXIge1xuICAgIGNvbnN0IGVudldvcmtlcklkID1cbiAgICAgIHByb2Nlc3MuZW52LldPUktFUl9JRCAhPT0gdW5kZWZpbmVkID8gTnVtYmVyKHByb2Nlc3MuZW52LldPUktFUl9JRCkgOiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIGVudldvcmtlcklkID8/IHRoaXMub3B0aW9ucy5jbHVzdGVyLndvcmtlcj8uaWQgPz8gLTE7XG4gIH1cblxuICAvKipcbiAgICogSGFuZGxlcyB1bmV4cGVjdGVkIHdvcmtlciBleGl0cyB3aXRoIHJlc3RhcnQgbG9naWNcbiAgICovXG4gIHByaXZhdGUgaGFuZGxlVW5leHBlY3RlZFdvcmtlckV4aXQod29ya2VyU3RhdGU6IFdvcmtlclN0YXRlKTogdm9pZCB7XG4gICAgY29uc3QgcmVzdGFydENvdW50ID0gd29ya2VyU3RhdGUucmVzdGFydENvdW50ICsgMTtcblxuICAgIGlmIChyZXN0YXJ0Q291bnQgPD0gdGhpcy5vcHRpb25zLnJlc3RhcnRNYXhUaW1lcykge1xuICAgICAgbG9nZ2VyLmVycm9yKFxuICAgICAgICBgUmVzdGFydGluZyB3b3JrZXIgJHt3b3JrZXJTdGF0ZS5pZH0gKHBpZDogJHt3b3JrZXJTdGF0ZS53b3JrZXIucHJvY2Vzcy5waWR9KSAoYXR0ZW1wdCAke3Jlc3RhcnRDb3VudH0vJHt0aGlzLm9wdGlvbnMucmVzdGFydE1heFRpbWVzfSlgLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IG5ld1dvcmtlciA9IHRoaXMuc3Bhd25Xb3JrZXIod29ya2VyU3RhdGUuaWQpO1xuICAgICAgY29uc3QgbmV3V29ya2VyU3RhdGUgPSB0aGlzLndvcmtlcnMuZ2V0KG5ld1dvcmtlci5pZCk7XG4gICAgICBpZiAobmV3V29ya2VyU3RhdGUpIHtcbiAgICAgICAgbmV3V29ya2VyU3RhdGUucmVzdGFydENvdW50ID0gcmVzdGFydENvdW50O1xuICAgICAgfVxuICAgICAgdGhpcy5lbWl0KCd3b3JrZXI6cmVzdGFydGVkJywgbmV3V29ya2VyLCB3b3JrZXJTdGF0ZS5yZXN0YXJ0Q291bnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgIGBSZXN0YXJ0IGxpbWl0ICgke3RoaXMub3B0aW9ucy5yZXN0YXJ0TWF4VGltZXN9KSBleGNlZWRlZCBmb3Igd29ya2VyICR7d29ya2VyU3RhdGUuaWR9IChwaWQ6ICR7d29ya2VyU3RhdGUud29ya2VyLnByb2Nlc3MucGlkfSksIHNodXR0aW5nIGRvd24gY2x1c3RlcmAsXG4gICAgICApO1xuICAgICAgdGhpcy5lbWl0KCd3b3JrZXI6cmVzdGFydC1saW1pdC1leGNlZWRlZCcsIHdvcmtlclN0YXRlLndvcmtlciwgd29ya2VyU3RhdGUucmVzdGFydENvdW50KTtcbiAgICAgIHRoaXMuc2h1dGRvd24oJ1JFU1RBUlRfTElNSVRfRVhDRUVERUQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU2h1dHMgZG93biB0aGUgcHJpbWFyeSBwcm9jZXNzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNodXRkb3duUHJpbWFyeShzaWduYWw/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsb2dnZXIuaW5mbyhcbiAgICAgIGBQcmltYXJ5IHByb2Nlc3MgKHBpZDogJHtwcm9jZXNzLnBpZH0pIHNodXR0aW5nIGRvd24gKHNpZ25hbDogJHtzaWduYWwgPz8gJ21hbnVhbCd9KWAsXG4gICAgKTtcblxuICAgIHRoaXMuc3RvcEhlYWx0aE1vbml0b3JpbmcoKTtcbiAgICB0aGlzLnJlbW92ZVNpZ25hbEhhbmRsZXJzKCk7XG5cbiAgICAvLyBTaHV0ZG93biBhbGwgd29ya2Vyc1xuICAgIGF3YWl0IHRoaXMuc2h1dGRvd25BbGxXb3JrZXJzKHNpZ25hbCk7XG5cbiAgICAvLyBFeGVjdXRlIHByaW1hcnkgc2h1dGRvd24gZnVuY3Rpb25cbiAgICBhd2FpdCBzYWZlRXhlY3V0ZShcbiAgICAgICgpID0+XG4gICAgICAgIHRpbWVvdXQoXG4gICAgICAgICAgdGhpcy5vcHRpb25zLnByaW1hcnlTaHV0ZG93bkZuKHNpZ25hbCksXG4gICAgICAgICAgdGhpcy5vcHRpb25zLnNodXRkb3duVGltZW91dCxcbiAgICAgICAgICAncHJpbWFyeSBzaHV0ZG93biB0aW1lb3V0JyxcbiAgICAgICAgKSxcbiAgICAgICdFcnJvciBpbiBwcmltYXJ5IHNodXRkb3duIGZ1bmN0aW9uJyxcbiAgICApO1xuXG4gICAgbG9nZ2VyLmluZm8oYFByaW1hcnkgcHJvY2VzcyAocGlkOiAke3Byb2Nlc3MucGlkfSkgc2h1dGRvd24gY29tcGxldGVkYCk7XG4gICAgdGhpcy5lbWl0KCdzaHV0ZG93bjpjb21wbGV0ZWQnKTtcbiAgICBwcm9jZXNzLmV4aXQoMCk7XG4gIH1cblxuICAvKipcbiAgICogU2h1dHMgZG93biBhbGwgd29ya2VycyBncmFjZWZ1bGx5XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHNodXRkb3duQWxsV29ya2VycyhzaWduYWw/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy53b3JrZXJzLnNpemUgPT09IDApIHJldHVybjtcblxuICAgIGxvZ2dlci5pbmZvKGBTaHV0dGluZyBkb3duICR7dGhpcy53b3JrZXJzLnNpemV9IHdvcmtlcnMuLi5gKTtcblxuICAgIC8vIE1hcmsgYWxsIHdvcmtlcnMgYXMgc2h1dHRpbmcgZG93biBhbmQgc2VuZCBzaHV0ZG93biBtZXNzYWdlXG4gICAgQXJyYXkuZnJvbSh0aGlzLndvcmtlcnMudmFsdWVzKCkpLmZvckVhY2goKHdvcmtlclN0YXRlKSA9PiB7XG4gICAgICB3b3JrZXJTdGF0ZS5pc1NodXR0aW5nRG93biA9IHRydWU7XG4gICAgICAvLyBPbmx5IHNlbmQgc2h1dGRvd24gbWVzc2FnZSBpZiB3b3JrZXIgaXMgc3RpbGwgY29ubmVjdGVkXG4gICAgICBpZiAoIXdvcmtlclN0YXRlLndvcmtlci5pc0RlYWQoKSAmJiB3b3JrZXJTdGF0ZS53b3JrZXIucHJvY2Vzcy5jb25uZWN0ZWQpIHtcbiAgICAgICAgY29uc3Qgc2h1dGRvd25NZXNzYWdlOiBTaHV0ZG93bk1lc3NhZ2UgPSB7XG4gICAgICAgICAgdHlwZTogJ3NodXRkb3duJyxcbiAgICAgICAgICBzaWduYWwsXG4gICAgICAgIH07XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgd29ya2VyU3RhdGUud29ya2VyLnNlbmQoc2h1dGRvd25NZXNzYWdlKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAvLyBXb3JrZXIgSVBDIGNoYW5uZWwgaXMgYWxyZWFkeSBjbG9zZWQsIHdoaWNoIGlzIGZpbmVcbiAgICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICAgIGBGYWlsZWQgdG8gc2VuZCBzaHV0ZG93biBtZXNzYWdlIHRvIHdvcmtlciAke3dvcmtlclN0YXRlLmlkfSAocGlkOiAke1xuICAgICAgICAgICAgICB3b3JrZXJTdGF0ZS53b3JrZXIucHJvY2Vzcy5waWRcbiAgICAgICAgICAgIH0pOiAke2Vycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKX1gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIFdhaXQgZm9yIHdvcmtlcnMgdG8gZXhpdCBncmFjZWZ1bGx5IG9yIHRpbWVvdXRcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGltZW91dChcbiAgICAgICAgdGhpcy53YWl0Rm9yQWxsV29ya2Vyc1RvRXhpdCgpLFxuICAgICAgICB0aGlzLm9wdGlvbnMuc2h1dGRvd25UaW1lb3V0LFxuICAgICAgICAnV29ya2VyIHNodXRkb3duIHRpbWVvdXQnLFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nZ2VyLmVycm9yKCdHcmFjZWZ1bCBzaHV0ZG93biBmb3Igd29ya2VycyB0aW1lZCBvdXQsIGZvcmNpbmcgc2h1dGRvd24nKTtcbiAgICAgIHRoaXMuZm9yY2VLaWxsQWxsV29ya2VycygpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXYWl0cyBmb3IgYWxsIHdvcmtlcnMgdG8gZXhpdFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB3YWl0Rm9yQWxsV29ya2Vyc1RvRXhpdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB3aGlsZSAodGhpcy53b3JrZXJzLnNpemUgPiAwKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tYXdhaXQtaW4tbG9vcFxuICAgICAgYXdhaXQgZGVsYXkoMTAwKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRm9yY2Uga2lsbHMgYWxsIHJlbWFpbmluZyB3b3JrZXJzXG4gICAqL1xuICBwcml2YXRlIGZvcmNlS2lsbEFsbFdvcmtlcnMoKTogdm9pZCB7XG4gICAgQXJyYXkuZnJvbSh0aGlzLndvcmtlcnMudmFsdWVzKCkpLmZvckVhY2goKHdvcmtlclN0YXRlKSA9PiB7XG4gICAgICBsb2dnZXIuZXJyb3IoXG4gICAgICAgIGBGb3JjZSBraWxsaW5nIHdvcmtlciAke3dvcmtlclN0YXRlLmlkfSAocGlkOiAke3dvcmtlclN0YXRlLndvcmtlci5wcm9jZXNzLnBpZH0pYCxcbiAgICAgICk7XG4gICAgICB3b3JrZXJTdGF0ZS53b3JrZXIua2lsbCgnU0lHS0lMTCcpO1xuICAgIH0pO1xuICAgIHRoaXMud29ya2Vycy5jbGVhcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNodXRzIGRvd24gYSB3b3JrZXIgcHJvY2Vzc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzaHV0ZG93bldvcmtlcihzaWduYWw/OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsb2dnZXIuaW5mbyhcbiAgICAgIGBXb3JrZXIgJHt0aGlzLmdldEN1cnJlbnRXb3JrZXJJZCgpfSAocGlkOiAke3Byb2Nlc3MucGlkfSkgc2h1dHRpbmcgZG93biAoc2lnbmFsOiAke1xuICAgICAgICBzaWduYWwgPz8gJ21hbnVhbCdcbiAgICAgIH0pYCxcbiAgICApO1xuXG4gICAgdGhpcy5yZW1vdmVTaWduYWxIYW5kbGVycygpO1xuXG4gICAgLy8gRXhlY3V0ZSB3b3JrZXIgc2h1dGRvd24gZnVuY3Rpb25cbiAgICBhd2FpdCBzYWZlRXhlY3V0ZShcbiAgICAgICgpID0+XG4gICAgICAgIHRpbWVvdXQoXG4gICAgICAgICAgdGhpcy5vcHRpb25zLndvcmtlclNodXRkb3duRm4oc2lnbmFsKSxcbiAgICAgICAgICB0aGlzLm9wdGlvbnMuc2h1dGRvd25UaW1lb3V0LFxuICAgICAgICAgICd3b3JrZXIgc2h1dGRvd24gdGltZW91dCcsXG4gICAgICAgICksXG4gICAgICBgRXJyb3IgaW4gd29ya2VyICR7dGhpcy5nZXRDdXJyZW50V29ya2VySWQoKX0gKHBpZDogJHtwcm9jZXNzLnBpZH0pIHNodXRkb3duIGZ1bmN0aW9uYCxcbiAgICApO1xuXG4gICAgbG9nZ2VyLmluZm8oYFdvcmtlciAke3RoaXMuZ2V0Q3VycmVudFdvcmtlcklkKCl9IChwaWQ6ICR7cHJvY2Vzcy5waWR9KSBzaHV0ZG93biBjb21wbGV0ZWRgKTtcbiAgICBwcm9jZXNzLmV4aXQoMCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgY3VycmVudCBudW1iZXIgb2YgYWN0aXZlIHdvcmtlcnNcbiAgICovXG4gIHB1YmxpYyBnZXRXb3JrZXJDb3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLndvcmtlcnMuc2l6ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGluZm9ybWF0aW9uIGFib3V0IGFsbCB3b3JrZXJzXG4gICAqL1xuICBwdWJsaWMgZ2V0V29ya2VySW5mbygpOiBBcnJheTx7IGlkOiBudW1iZXI7IHBpZDogbnVtYmVyOyByZXN0YXJ0Q291bnQ6IG51bWJlciB9PiB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy53b3JrZXJzLnZhbHVlcygpKS5tYXAoKHN0YXRlKSA9PiAoe1xuICAgICAgaWQ6IHN0YXRlLmlkLFxuICAgICAgcGlkOiBzdGF0ZS53b3JrZXIucHJvY2Vzcy5waWQgPz8gLTEsXG4gICAgICByZXN0YXJ0Q291bnQ6IHN0YXRlLnJlc3RhcnRDb3VudCxcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjbHVzdGVyIGlzIGN1cnJlbnRseSBzdGFydGVkXG4gICAqL1xuICBwdWJsaWMgaXNTdGFydGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnN0YXJ0ZWQ7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBjbHVzdGVyIGlzIGN1cnJlbnRseSBzaHV0dGluZyBkb3duXG4gICAqL1xuICBwdWJsaWMgaXNTaHV0ZG93bigpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1NodXR0aW5nRG93bjtcbiAgfVxufVxuXG4vLyBUeXBlLXNhZmUgZXZlbnQgZW1pdHRlciBpbnRlcmZhY2VcbmV4cG9ydCBpbnRlcmZhY2UgQ2x1c3Rlck1hbmFnZXJFbWl0dGVyIHtcbiAgb248SyBleHRlbmRzIGtleW9mIENsdXN0ZXJNYW5hZ2VyRXZlbnRzPihldmVudDogSywgbGlzdGVuZXI6IENsdXN0ZXJNYW5hZ2VyRXZlbnRzW0tdKTogdGhpcztcbiAgZW1pdDxLIGV4dGVuZHMga2V5b2YgQ2x1c3Rlck1hbmFnZXJFdmVudHM+KFxuICAgIGV2ZW50OiBLLFxuICAgIC4uLmFyZ3M6IFBhcmFtZXRlcnM8Q2x1c3Rlck1hbmFnZXJFdmVudHNbS10+XG4gICk6IGJvb2xlYW47XG59XG4iXX0=
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Worker } from 'cluster';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for ClusterManager
|
|
4
|
+
*/
|
|
5
|
+
export interface ClusterManagerOptions {
|
|
6
|
+
cluster?: Cluster;
|
|
7
|
+
/** Function to execute in the primary process during start */
|
|
8
|
+
primaryFn?: () => void | Promise<void>;
|
|
9
|
+
/** Function to execute in the primary process after all workers have been shutdown and just before primary process shutdown */
|
|
10
|
+
primaryShutdownFn?: (signal?: string) => Promise<void>;
|
|
11
|
+
/** Function to execute in worker processes during start */
|
|
12
|
+
workerFn?: () => void | Promise<void>;
|
|
13
|
+
/** Function to execute in worker processes just before worker process shutdown */
|
|
14
|
+
workerShutdownFn?: (signal?: string) => Promise<void>;
|
|
15
|
+
/** Frequency of worker health checks in milliseconds (default: 10000) */
|
|
16
|
+
pingFrequency?: number;
|
|
17
|
+
/** Timeout for worker ping responses in milliseconds (default: 30000) */
|
|
18
|
+
pingTimeout?: number;
|
|
19
|
+
/** Callback to determine action when a stuck worker is killed, if true a new worker will be spawned, if false cluster will shutdown (default: true) */
|
|
20
|
+
stuckWorkerRespawnFunc?: (worker: Worker) => boolean;
|
|
21
|
+
/** Maximum number of times to restart a worker after it has exited unexpectedly (default: 3) */
|
|
22
|
+
restartMaxTimes?: number;
|
|
23
|
+
/** Signals that trigger shutdown (default: ['SIGINT', 'SIGTERM']) */
|
|
24
|
+
shutdownSignals?: NodeJS.Signals[];
|
|
25
|
+
/** Timeout for graceful worker shutdown in milliseconds (default: 30000) */
|
|
26
|
+
shutdownTimeout?: number;
|
|
27
|
+
/** Number of worker processes to spawn (default: number of CPU cores) */
|
|
28
|
+
numWorkers?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface Cluster {
|
|
31
|
+
worker?: Worker | undefined;
|
|
32
|
+
readonly isPrimary: boolean;
|
|
33
|
+
fork(env?: any): Worker;
|
|
34
|
+
on(event: string, listener: (...args: any[]) => void): Cluster;
|
|
35
|
+
on(event: 'exit', listener: (worker: Worker, code: number, signal: string) => void): this;
|
|
36
|
+
on(event: 'online', listener: (worker: Worker) => void): this;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Internal worker state tracking
|
|
40
|
+
*/
|
|
41
|
+
export interface WorkerState {
|
|
42
|
+
id: number;
|
|
43
|
+
worker: Worker;
|
|
44
|
+
restartCount: number;
|
|
45
|
+
lastPing: number;
|
|
46
|
+
pendingPing: boolean;
|
|
47
|
+
isShuttingDown: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Events emitted by ClusterManager
|
|
51
|
+
*/
|
|
52
|
+
export interface ClusterManagerEvents {
|
|
53
|
+
'worker:started': (worker: Worker) => void;
|
|
54
|
+
'worker:died': (worker: Worker, code: number | null, signal: string | null) => void;
|
|
55
|
+
'worker:stuck': (worker: Worker) => void;
|
|
56
|
+
'worker:restarted': (worker: Worker, restartCount: number) => void;
|
|
57
|
+
'worker:restart-limit-exceeded': (worker: Worker, restartCount: number) => void;
|
|
58
|
+
'shutdown:started': (signal?: string) => void;
|
|
59
|
+
'shutdown:completed': () => void;
|
|
60
|
+
error: (error: Error) => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Message types for inter-process communication
|
|
64
|
+
*/
|
|
65
|
+
export interface PingMessage {
|
|
66
|
+
type: 'ping';
|
|
67
|
+
timestamp: number;
|
|
68
|
+
}
|
|
69
|
+
export interface PongMessage {
|
|
70
|
+
type: 'pong';
|
|
71
|
+
timestamp: number;
|
|
72
|
+
}
|
|
73
|
+
export interface ShutdownMessage {
|
|
74
|
+
type: 'shutdown';
|
|
75
|
+
signal?: string;
|
|
76
|
+
}
|
|
77
|
+
export type IPCMessage = PingMessage | PongMessage | ShutdownMessage;
|
|
78
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cluster/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2x1c3Rlci90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgV29ya2VyIH0gZnJvbSAnY2x1c3Rlcic7XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciBDbHVzdGVyTWFuYWdlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsdXN0ZXJNYW5hZ2VyT3B0aW9ucyB7XG4gIGNsdXN0ZXI/OiBDbHVzdGVyO1xuXG4gIC8qKiBGdW5jdGlvbiB0byBleGVjdXRlIGluIHRoZSBwcmltYXJ5IHByb2Nlc3MgZHVyaW5nIHN0YXJ0ICovXG4gIHByaW1hcnlGbj86ICgpID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKiBGdW5jdGlvbiB0byBleGVjdXRlIGluIHRoZSBwcmltYXJ5IHByb2Nlc3MgYWZ0ZXIgYWxsIHdvcmtlcnMgaGF2ZSBiZWVuIHNodXRkb3duIGFuZCBqdXN0IGJlZm9yZSBwcmltYXJ5IHByb2Nlc3Mgc2h1dGRvd24gKi9cbiAgcHJpbWFyeVNodXRkb3duRm4/OiAoc2lnbmFsPzogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+O1xuXG4gIC8qKiBGdW5jdGlvbiB0byBleGVjdXRlIGluIHdvcmtlciBwcm9jZXNzZXMgZHVyaW5nIHN0YXJ0ICovXG4gIHdvcmtlckZuPzogKCkgPT4gdm9pZCB8IFByb21pc2U8dm9pZD47XG5cbiAgLyoqIEZ1bmN0aW9uIHRvIGV4ZWN1dGUgaW4gd29ya2VyIHByb2Nlc3NlcyBqdXN0IGJlZm9yZSB3b3JrZXIgcHJvY2VzcyBzaHV0ZG93biAqL1xuICB3b3JrZXJTaHV0ZG93bkZuPzogKHNpZ25hbD86IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPjtcblxuICAvKiogRnJlcXVlbmN5IG9mIHdvcmtlciBoZWFsdGggY2hlY2tzIGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMTAwMDApICovXG4gIHBpbmdGcmVxdWVuY3k/OiBudW1iZXI7XG5cbiAgLyoqIFRpbWVvdXQgZm9yIHdvcmtlciBwaW5nIHJlc3BvbnNlcyBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQ6IDMwMDAwKSAqL1xuICBwaW5nVGltZW91dD86IG51bWJlcjtcblxuICAvKiogQ2FsbGJhY2sgdG8gZGV0ZXJtaW5lIGFjdGlvbiB3aGVuIGEgc3R1Y2sgd29ya2VyIGlzIGtpbGxlZCwgaWYgdHJ1ZSBhIG5ldyB3b3JrZXIgd2lsbCBiZSBzcGF3bmVkLCBpZiBmYWxzZSBjbHVzdGVyIHdpbGwgc2h1dGRvd24gKGRlZmF1bHQ6IHRydWUpICovXG4gIHN0dWNrV29ya2VyUmVzcGF3bkZ1bmM/OiAod29ya2VyOiBXb3JrZXIpID0+IGJvb2xlYW47XG5cbiAgLyoqIE1heGltdW0gbnVtYmVyIG9mIHRpbWVzIHRvIHJlc3RhcnQgYSB3b3JrZXIgYWZ0ZXIgaXQgaGFzIGV4aXRlZCB1bmV4cGVjdGVkbHkgKGRlZmF1bHQ6IDMpICovXG4gIHJlc3RhcnRNYXhUaW1lcz86IG51bWJlcjtcblxuICAvKiogU2lnbmFscyB0aGF0IHRyaWdnZXIgc2h1dGRvd24gKGRlZmF1bHQ6IFsnU0lHSU5UJywgJ1NJR1RFUk0nXSkgKi9cbiAgc2h1dGRvd25TaWduYWxzPzogTm9kZUpTLlNpZ25hbHNbXTtcblxuICAvKiogVGltZW91dCBmb3IgZ3JhY2VmdWwgd29ya2VyIHNodXRkb3duIGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdDogMzAwMDApICovXG4gIHNodXRkb3duVGltZW91dD86IG51bWJlcjtcblxuICAvKiogTnVtYmVyIG9mIHdvcmtlciBwcm9jZXNzZXMgdG8gc3Bhd24gKGRlZmF1bHQ6IG51bWJlciBvZiBDUFUgY29yZXMpICovXG4gIG51bVdvcmtlcnM/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2x1c3RlciB7XG4gIHdvcmtlcj86IFdvcmtlciB8IHVuZGVmaW5lZDtcbiAgcmVhZG9ubHkgaXNQcmltYXJ5OiBib29sZWFuO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICBmb3JrKGVudj86IGFueSk6IFdvcmtlcjtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgb24oZXZlbnQ6IHN0cmluZywgbGlzdGVuZXI6ICguLi5hcmdzOiBhbnlbXSkgPT4gdm9pZCk6IENsdXN0ZXI7XG4gIG9uKGV2ZW50OiAnZXhpdCcsIGxpc3RlbmVyOiAod29ya2VyOiBXb3JrZXIsIGNvZGU6IG51bWJlciwgc2lnbmFsOiBzdHJpbmcpID0+IHZvaWQpOiB0aGlzO1xuICBvbihldmVudDogJ29ubGluZScsIGxpc3RlbmVyOiAod29ya2VyOiBXb3JrZXIpID0+IHZvaWQpOiB0aGlzO1xufVxuLyoqXG4gKiBJbnRlcm5hbCB3b3JrZXIgc3RhdGUgdHJhY2tpbmdcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXb3JrZXJTdGF0ZSB7XG4gIGlkOiBudW1iZXI7XG4gIHdvcmtlcjogV29ya2VyO1xuICByZXN0YXJ0Q291bnQ6IG51bWJlcjsgLy8gTnVtYmVyIG9mIHRpbWVzIHRoZSB3b3JrZXIgaGFzIGJlZW4gcmVzdGFydGVkXG4gIGxhc3RQaW5nOiBudW1iZXI7IC8vIFRpbWVzdGFtcCBvZiB0aGUgbGFzdCBwaW5nIHJlY2VpdmVkIGZyb20gdGhlIHdvcmtlclxuICBwZW5kaW5nUGluZzogYm9vbGVhbjsgLy8gV2hldGhlciBhIHBpbmcgcmVzcG9uc2UgaXMgcGVuZGluZyBmcm9tIHRoZSB3b3JrZXJcbiAgaXNTaHV0dGluZ0Rvd246IGJvb2xlYW47IC8vIFdoZXRoZXIgdGhlIHdvcmtlciBpcyBpbiB0aGUgcHJvY2VzcyBvZiBzaHV0dGluZyBkb3duXG59XG5cbi8qKlxuICogRXZlbnRzIGVtaXR0ZWQgYnkgQ2x1c3Rlck1hbmFnZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDbHVzdGVyTWFuYWdlckV2ZW50cyB7XG4gICd3b3JrZXI6c3RhcnRlZCc6ICh3b3JrZXI6IFdvcmtlcikgPT4gdm9pZDtcbiAgJ3dvcmtlcjpkaWVkJzogKHdvcmtlcjogV29ya2VyLCBjb2RlOiBudW1iZXIgfCBudWxsLCBzaWduYWw6IHN0cmluZyB8IG51bGwpID0+IHZvaWQ7XG4gICd3b3JrZXI6c3R1Y2snOiAod29ya2VyOiBXb3JrZXIpID0+IHZvaWQ7XG4gICd3b3JrZXI6cmVzdGFydGVkJzogKHdvcmtlcjogV29ya2VyLCByZXN0YXJ0Q291bnQ6IG51bWJlcikgPT4gdm9pZDtcbiAgJ3dvcmtlcjpyZXN0YXJ0LWxpbWl0LWV4Y2VlZGVkJzogKHdvcmtlcjogV29ya2VyLCByZXN0YXJ0Q291bnQ6IG51bWJlcikgPT4gdm9pZDtcbiAgJ3NodXRkb3duOnN0YXJ0ZWQnOiAoc2lnbmFsPzogc3RyaW5nKSA9PiB2b2lkO1xuICAnc2h1dGRvd246Y29tcGxldGVkJzogKCkgPT4gdm9pZDtcbiAgZXJyb3I6IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG59XG5cbi8qKlxuICogTWVzc2FnZSB0eXBlcyBmb3IgaW50ZXItcHJvY2VzcyBjb21tdW5pY2F0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUGluZ01lc3NhZ2Uge1xuICB0eXBlOiAncGluZyc7XG4gIHRpbWVzdGFtcDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBvbmdNZXNzYWdlIHtcbiAgdHlwZTogJ3BvbmcnO1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTaHV0ZG93bk1lc3NhZ2Uge1xuICB0eXBlOiAnc2h1dGRvd24nO1xuICBzaWduYWw/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCB0eXBlIElQQ01lc3NhZ2UgPSBQaW5nTWVzc2FnZSB8IFBvbmdNZXNzYWdlIHwgU2h1dGRvd25NZXNzYWdlO1xuIl19
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for ClusterManager
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Creates a promise that resolves after the specified timeout
|
|
6
|
+
*/
|
|
7
|
+
export declare function delay(ms: number): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Creates a promise that rejects after the specified timeout
|
|
10
|
+
*/
|
|
11
|
+
export declare function timeout<T>(promise: Promise<T>, ms: number, errorMessage?: string): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Safely executes an async function with error handling
|
|
14
|
+
*/
|
|
15
|
+
export declare function safeExecute<T>(fn: () => T | Promise<T>, errorMessage: string): Promise<T | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* Validates ClusterManagerOptions and provides defaults
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateAndDefaultOptions(options: import('./types').ClusterManagerOptions): Required<import('./types').ClusterManagerOptions>;
|
|
20
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/cluster/utils.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAa7F;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,CAAC,EACjC,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAOxB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,SAAS,EAAE,qBAAqB,GAC/C,QAAQ,CAAC,OAAO,SAAS,EAAE,qBAAqB,CAAC,CAgBnD"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.delay = delay;
|
|
40
|
+
exports.timeout = timeout;
|
|
41
|
+
exports.safeExecute = safeExecute;
|
|
42
|
+
exports.validateAndDefaultOptions = validateAndDefaultOptions;
|
|
43
|
+
const os_1 = require("os");
|
|
44
|
+
const cluster_1 = __importDefault(require("cluster"));
|
|
45
|
+
const logger = __importStar(require("../logger"));
|
|
46
|
+
/**
|
|
47
|
+
* Utility functions for ClusterManager
|
|
48
|
+
*/
|
|
49
|
+
/**
|
|
50
|
+
* Creates a promise that resolves after the specified timeout
|
|
51
|
+
*/
|
|
52
|
+
function delay(ms) {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
setTimeout(resolve, ms);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Creates a promise that rejects after the specified timeout
|
|
59
|
+
*/
|
|
60
|
+
function timeout(promise, ms, errorMessage) {
|
|
61
|
+
let timeoutHandle;
|
|
62
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
63
|
+
timeoutHandle = setTimeout(() => {
|
|
64
|
+
reject(new Error(errorMessage ?? `Operation timed out after ${ms}ms`));
|
|
65
|
+
}, ms);
|
|
66
|
+
});
|
|
67
|
+
return Promise.race([
|
|
68
|
+
promise.finally(() => {
|
|
69
|
+
clearTimeout(timeoutHandle);
|
|
70
|
+
}),
|
|
71
|
+
timeoutPromise,
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Safely executes an async function with error handling
|
|
76
|
+
*/
|
|
77
|
+
async function safeExecute(fn, errorMessage) {
|
|
78
|
+
try {
|
|
79
|
+
return await fn();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
logger.error(`${errorMessage}:`, error);
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates ClusterManagerOptions and provides defaults
|
|
88
|
+
*/
|
|
89
|
+
function validateAndDefaultOptions(options) {
|
|
90
|
+
const numCPUs = (0, os_1.cpus)().length;
|
|
91
|
+
return {
|
|
92
|
+
cluster: options.cluster ?? cluster_1.default,
|
|
93
|
+
primaryFn: options.primaryFn ?? (() => { }),
|
|
94
|
+
primaryShutdownFn: options.primaryShutdownFn ?? (async () => { }),
|
|
95
|
+
workerFn: options.workerFn ?? (() => { }),
|
|
96
|
+
workerShutdownFn: options.workerShutdownFn ?? (async () => { }),
|
|
97
|
+
pingFrequency: options.pingFrequency ?? 10000,
|
|
98
|
+
pingTimeout: options.pingTimeout ?? 30000,
|
|
99
|
+
stuckWorkerRespawnFunc: options.stuckWorkerRespawnFunc ?? (() => true),
|
|
100
|
+
restartMaxTimes: options.restartMaxTimes ?? 3,
|
|
101
|
+
shutdownSignals: options.shutdownSignals ?? ['SIGINT', 'SIGTERM'],
|
|
102
|
+
shutdownTimeout: options.shutdownTimeout ?? 30000,
|
|
103
|
+
numWorkers: options.numWorkers ?? numCPUs,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY2x1c3Rlci91dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQVdBLHNCQUlDO0FBS0QsMEJBYUM7QUFLRCxrQ0FVQztBQUtELDhEQWtCQztBQXZFRCwyQkFBMEI7QUFDMUIsc0RBQThCO0FBQzlCLGtEQUFvQztBQUVwQzs7R0FFRztBQUVIOztHQUVHO0FBQ0gsU0FBZ0IsS0FBSyxDQUFDLEVBQVU7SUFDOUIsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1FBQzdCLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDMUIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixPQUFPLENBQUksT0FBbUIsRUFBRSxFQUFVLEVBQUUsWUFBcUI7SUFDL0UsSUFBSSxhQUE2QixDQUFDO0lBQ2xDLE1BQU0sY0FBYyxHQUFHLElBQUksT0FBTyxDQUFRLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3RELGFBQWEsR0FBRyxVQUFVLENBQUMsR0FBRyxFQUFFO1lBQzlCLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxZQUFZLElBQUksNkJBQTZCLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUN6RSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDVCxDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQztRQUNsQixPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTtZQUNuQixZQUFZLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDOUIsQ0FBQyxDQUFDO1FBQ0YsY0FBYztLQUNmLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7R0FFRztBQUNJLEtBQUssVUFBVSxXQUFXLENBQy9CLEVBQXdCLEVBQ3hCLFlBQW9CO0lBRXBCLElBQUksQ0FBQztRQUNILE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQztJQUNwQixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxZQUFZLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN4QyxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IseUJBQXlCLENBQ3ZDLE9BQWdEO0lBRWhELE1BQU0sT0FBTyxHQUFHLElBQUEsU0FBSSxHQUFFLENBQUMsTUFBTSxDQUFDO0lBQzlCLE9BQU87UUFDTCxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sSUFBSSxpQkFBTztRQUNuQyxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVMsSUFBSSxDQUFDLEdBQVMsRUFBRSxHQUFFLENBQUMsQ0FBQztRQUNoRCxpQkFBaUIsRUFBRSxPQUFPLENBQUMsaUJBQWlCLElBQUksQ0FBQyxLQUFLLElBQW1CLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDL0UsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRLElBQUksQ0FBQyxHQUFTLEVBQUUsR0FBRSxDQUFDLENBQUM7UUFDOUMsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixJQUFJLENBQUMsS0FBSyxJQUFtQixFQUFFLEdBQUUsQ0FBQyxDQUFDO1FBQzdFLGFBQWEsRUFBRSxPQUFPLENBQUMsYUFBYSxJQUFJLEtBQUs7UUFDN0MsV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXLElBQUksS0FBSztRQUN6QyxzQkFBc0IsRUFBRSxPQUFPLENBQUMsc0JBQXNCLElBQUksQ0FBQyxHQUFZLEVBQUUsQ0FBQyxJQUFJLENBQUM7UUFDL0UsZUFBZSxFQUFFLE9BQU8sQ0FBQyxlQUFlLElBQUksQ0FBQztRQUM3QyxlQUFlLEVBQUUsT0FBTyxDQUFDLGVBQWUsSUFBSSxDQUFDLFFBQVEsRUFBRSxTQUFTLENBQUM7UUFDakUsZUFBZSxFQUFFLE9BQU8sQ0FBQyxlQUFlLElBQUksS0FBSztRQUNqRCxVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVUsSUFBSSxPQUFPO0tBQzFDLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3B1cyB9IGZyb20gJ29zJztcbmltcG9ydCBjbHVzdGVyIGZyb20gJ2NsdXN0ZXInO1xuaW1wb3J0ICogYXMgbG9nZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbnMgZm9yIENsdXN0ZXJNYW5hZ2VyXG4gKi9cblxuLyoqXG4gKiBDcmVhdGVzIGEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBzcGVjaWZpZWQgdGltZW91dFxuICovXG5leHBvcnQgZnVuY3Rpb24gZGVsYXkobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKTtcbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHByb21pc2UgdGhhdCByZWplY3RzIGFmdGVyIHRoZSBzcGVjaWZpZWQgdGltZW91dFxuICovXG5leHBvcnQgZnVuY3Rpb24gdGltZW91dDxUPihwcm9taXNlOiBQcm9taXNlPFQ+LCBtczogbnVtYmVyLCBlcnJvck1lc3NhZ2U/OiBzdHJpbmcpOiBQcm9taXNlPFQ+IHtcbiAgbGV0IHRpbWVvdXRIYW5kbGU6IE5vZGVKUy5UaW1lb3V0O1xuICBjb25zdCB0aW1lb3V0UHJvbWlzZSA9IG5ldyBQcm9taXNlPG5ldmVyPigoXywgcmVqZWN0KSA9PiB7XG4gICAgdGltZW91dEhhbmRsZSA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgcmVqZWN0KG5ldyBFcnJvcihlcnJvck1lc3NhZ2UgPz8gYE9wZXJhdGlvbiB0aW1lZCBvdXQgYWZ0ZXIgJHttc31tc2ApKTtcbiAgICB9LCBtcyk7XG4gIH0pO1xuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcbiAgICBwcm9taXNlLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRIYW5kbGUpO1xuICAgIH0pLFxuICAgIHRpbWVvdXRQcm9taXNlLFxuICBdKTtcbn1cblxuLyoqXG4gKiBTYWZlbHkgZXhlY3V0ZXMgYW4gYXN5bmMgZnVuY3Rpb24gd2l0aCBlcnJvciBoYW5kbGluZ1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2FmZUV4ZWN1dGU8VD4oXG4gIGZuOiAoKSA9PiBUIHwgUHJvbWlzZTxUPixcbiAgZXJyb3JNZXNzYWdlOiBzdHJpbmcsXG4pOiBQcm9taXNlPFQgfCB1bmRlZmluZWQ+IHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gYXdhaXQgZm4oKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2dnZXIuZXJyb3IoYCR7ZXJyb3JNZXNzYWdlfTpgLCBlcnJvcik7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyBDbHVzdGVyTWFuYWdlck9wdGlvbnMgYW5kIHByb3ZpZGVzIGRlZmF1bHRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUFuZERlZmF1bHRPcHRpb25zKFxuICBvcHRpb25zOiBpbXBvcnQoJy4vdHlwZXMnKS5DbHVzdGVyTWFuYWdlck9wdGlvbnMsXG4pOiBSZXF1aXJlZDxpbXBvcnQoJy4vdHlwZXMnKS5DbHVzdGVyTWFuYWdlck9wdGlvbnM+IHtcbiAgY29uc3QgbnVtQ1BVcyA9IGNwdXMoKS5sZW5ndGg7XG4gIHJldHVybiB7XG4gICAgY2x1c3Rlcjogb3B0aW9ucy5jbHVzdGVyID8/IGNsdXN0ZXIsXG4gICAgcHJpbWFyeUZuOiBvcHRpb25zLnByaW1hcnlGbiA/PyAoKCk6IHZvaWQgPT4ge30pLFxuICAgIHByaW1hcnlTaHV0ZG93bkZuOiBvcHRpb25zLnByaW1hcnlTaHV0ZG93bkZuID8/IChhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7fSksXG4gICAgd29ya2VyRm46IG9wdGlvbnMud29ya2VyRm4gPz8gKCgpOiB2b2lkID0+IHt9KSxcbiAgICB3b3JrZXJTaHV0ZG93bkZuOiBvcHRpb25zLndvcmtlclNodXRkb3duRm4gPz8gKGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHt9KSxcbiAgICBwaW5nRnJlcXVlbmN5OiBvcHRpb25zLnBpbmdGcmVxdWVuY3kgPz8gMTAwMDAsXG4gICAgcGluZ1RpbWVvdXQ6IG9wdGlvbnMucGluZ1RpbWVvdXQgPz8gMzAwMDAsXG4gICAgc3R1Y2tXb3JrZXJSZXNwYXduRnVuYzogb3B0aW9ucy5zdHVja1dvcmtlclJlc3Bhd25GdW5jID8/ICgoKTogYm9vbGVhbiA9PiB0cnVlKSxcbiAgICByZXN0YXJ0TWF4VGltZXM6IG9wdGlvbnMucmVzdGFydE1heFRpbWVzID8/IDMsXG4gICAgc2h1dGRvd25TaWduYWxzOiBvcHRpb25zLnNodXRkb3duU2lnbmFscyA/PyBbJ1NJR0lOVCcsICdTSUdURVJNJ10sXG4gICAgc2h1dGRvd25UaW1lb3V0OiBvcHRpb25zLnNodXRkb3duVGltZW91dCA/PyAzMDAwMCxcbiAgICBudW1Xb3JrZXJzOiBvcHRpb25zLm51bVdvcmtlcnMgPz8gbnVtQ1BVcyxcbiAgfTtcbn1cbiJdfQ==
|
package/build/index.d.ts
CHANGED
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,QAAQ,CAAC;AACvB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -29,4 +29,5 @@ __exportStar(require("./network"), exports);
|
|
|
29
29
|
__exportStar(require("./utils"), exports);
|
|
30
30
|
__exportStar(require("./constants"), exports);
|
|
31
31
|
__exportStar(require("./sdks"), exports);
|
|
32
|
-
|
|
32
|
+
__exportStar(require("./cluster"), exports);
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxnRUFBdUM7QUFZOUIsbUJBWkYsbUJBQVEsQ0FZRTtBQVZqQiwwQ0FBd0I7QUFDeEIseUNBQXVCO0FBQ3ZCLDJDQUF5QjtBQUN6QiwyQ0FBeUI7QUFDekIsc0RBQW9DO0FBQ3BDLDRDQUEwQjtBQUMxQiwwQ0FBd0I7QUFDeEIsOENBQTRCO0FBQzVCLHlDQUF1QjtBQUN2Qiw0Q0FBMEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc2V0VmFsdWUgZnJvbSAnLi9saWIvc2V0LXZhbHVlJztcblxuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG5leHBvcnQgKiBmcm9tICcuL3RhZ3MnO1xuZXhwb3J0ICogZnJvbSAnLi9lcnJvcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9sb2dnZXInO1xuZXhwb3J0ICogZnJvbSAnLi9zdHJ1Y3R1cmVkLWxvZ2dlcic7XG5leHBvcnQgKiBmcm9tICcuL25ldHdvcmsnO1xuZXhwb3J0ICogZnJvbSAnLi91dGlscyc7XG5leHBvcnQgKiBmcm9tICcuL2NvbnN0YW50cyc7XG5leHBvcnQgKiBmcm9tICcuL3Nka3MnO1xuZXhwb3J0ICogZnJvbSAnLi9jbHVzdGVyJztcbmV4cG9ydCB7IHNldFZhbHVlIH07XG4iXX0=
|