@kapeta/local-cluster-service 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/cjs/src/instanceManager.d.ts +4 -1
- package/dist/cjs/src/instanceManager.js +215 -191
- package/dist/esm/src/instanceManager.d.ts +4 -1
- package/dist/esm/src/instanceManager.js +215 -191
- package/package.json +3 -1
- package/src/instanceManager.ts +241 -211
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## [0.11.1](https://github.com/kapetacom/local-cluster-service/compare/v0.11.0...v0.11.1) (2023-07-31)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Ensure we do not attempt to start / stop the same instance at the ([493e077](https://github.com/kapetacom/local-cluster-service/commit/493e077d0c6acdbcc371dae2ef8b6fbf2478c950))
|
7
|
+
|
1
8
|
# [0.11.0](https://github.com/kapetacom/local-cluster-service/compare/v0.10.1...v0.11.0) (2023-07-31)
|
2
9
|
|
3
10
|
|
@@ -2,11 +2,13 @@ import { InstanceInfo, LogEntry } from './types';
|
|
2
2
|
export declare class InstanceManager {
|
3
3
|
private _interval;
|
4
4
|
private readonly _instances;
|
5
|
+
private readonly instanceLocks;
|
5
6
|
constructor();
|
6
7
|
private checkInstancesLater;
|
7
8
|
getInstances(): InstanceInfo[];
|
8
9
|
getInstancesForPlan(systemId: string): InstanceInfo[];
|
9
10
|
getInstance(systemId: string, instanceId: string): InstanceInfo | undefined;
|
11
|
+
private exclusive;
|
10
12
|
getLogs(systemId: string, instanceId: string): Promise<LogEntry[]>;
|
11
13
|
saveInternalInstance(instance: InstanceInfo): Promise<InstanceInfo>;
|
12
14
|
/**
|
@@ -15,9 +17,10 @@ export declare class InstanceManager {
|
|
15
17
|
*/
|
16
18
|
registerInstanceFromSDK(systemId: string, instanceId: string, info: Omit<InstanceInfo, 'systemId' | 'instanceId'>): Promise<InstanceInfo | undefined>;
|
17
19
|
private getHealthUrl;
|
18
|
-
markAsStopped(systemId: string, instanceId: string): void
|
20
|
+
markAsStopped(systemId: string, instanceId: string): Promise<void>;
|
19
21
|
startAllForPlan(systemId: string): Promise<InstanceInfo[]>;
|
20
22
|
stop(systemId: string, instanceId: string): Promise<void>;
|
23
|
+
private stopInner;
|
21
24
|
stopAllForPlan(systemId: string): Promise<void>;
|
22
25
|
start(systemId: string, instanceId: string): Promise<InstanceInfo>;
|
23
26
|
restart(systemId: string, instanceId: string): Promise<InstanceInfo>;
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.instanceManager = exports.InstanceManager = void 0;
|
7
7
|
const lodash_1 = __importDefault(require("lodash"));
|
8
8
|
const request_1 = __importDefault(require("request"));
|
9
|
+
const async_lock_1 = __importDefault(require("async-lock"));
|
9
10
|
const BlockInstanceRunner_1 = require("./utils/BlockInstanceRunner");
|
10
11
|
const storageService_1 = require("./storageService");
|
11
12
|
const socketManager_1 = require("./socketManager");
|
@@ -25,6 +26,7 @@ const MIN_TIME_RUNNING = 30000; //If something didnt run for more than 30 secs -
|
|
25
26
|
class InstanceManager {
|
26
27
|
_interval = undefined;
|
27
28
|
_instances = [];
|
29
|
+
instanceLocks = new async_lock_1.default();
|
28
30
|
constructor() {
|
29
31
|
this._instances = storageService_1.storageService.section('instances', []);
|
30
32
|
// We need to wait a bit before running the first check
|
@@ -56,6 +58,11 @@ class InstanceManager {
|
|
56
58
|
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
57
59
|
return this._instances.find((i) => i.systemId === systemId && i.instanceId === instanceId);
|
58
60
|
}
|
61
|
+
async exclusive(systemId, instanceId, fn) {
|
62
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
63
|
+
const key = `${systemId}/${instanceId}`;
|
64
|
+
return this.instanceLocks.acquire(key, fn);
|
65
|
+
}
|
59
66
|
async getLogs(systemId, instanceId) {
|
60
67
|
const instance = this.getInstance(systemId, instanceId);
|
61
68
|
if (!instance) {
|
@@ -111,57 +118,59 @@ class InstanceManager {
|
|
111
118
|
* which self-registers with the cluster service locally on startup.
|
112
119
|
*/
|
113
120
|
async registerInstanceFromSDK(systemId, instanceId, info) {
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
if (instance
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if (info.owner === types_1.InstanceOwner.EXTERNAL) {
|
125
|
-
//If instance was started externally - then we want to replace the internal instance with that
|
126
|
-
if (instance.owner === types_1.InstanceOwner.INTERNAL &&
|
127
|
-
(instance.status === types_1.InstanceStatus.READY ||
|
128
|
-
instance.status === types_1.InstanceStatus.STARTING ||
|
129
|
-
instance.status === types_1.InstanceStatus.UNHEALTHY)) {
|
130
|
-
throw new Error(`Instance ${instanceId} is already running`);
|
121
|
+
return this.exclusive(systemId, instanceId, async () => {
|
122
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
123
|
+
let instance = this.getInstance(systemId, instanceId);
|
124
|
+
//Get target address
|
125
|
+
const address = await serviceManager_1.serviceManager.getProviderAddress(systemId, instanceId, info.portType ?? DEFAULT_HEALTH_PORT_TYPE);
|
126
|
+
const healthUrl = this.getHealthUrl(info, address);
|
127
|
+
if (instance) {
|
128
|
+
if (instance.status === types_1.InstanceStatus.STOPPING && instance.desiredStatus === types_1.DesiredInstanceStatus.STOP) {
|
129
|
+
//If instance is stopping do not interfere
|
130
|
+
return;
|
131
131
|
}
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
132
|
+
if (info.owner === types_1.InstanceOwner.EXTERNAL) {
|
133
|
+
//If instance was started externally - then we want to replace the internal instance with that
|
134
|
+
if (instance.owner === types_1.InstanceOwner.INTERNAL &&
|
135
|
+
(instance.status === types_1.InstanceStatus.READY ||
|
136
|
+
instance.status === types_1.InstanceStatus.STARTING ||
|
137
|
+
instance.status === types_1.InstanceStatus.UNHEALTHY)) {
|
138
|
+
throw new Error(`Instance ${instanceId} is already running`);
|
139
|
+
}
|
140
|
+
instance.desiredStatus = info.desiredStatus;
|
141
|
+
instance.owner = info.owner;
|
142
|
+
instance.status = types_1.InstanceStatus.STARTING;
|
143
|
+
instance.startedAt = Date.now();
|
144
|
+
}
|
145
|
+
instance.pid = info.pid;
|
146
|
+
instance.address = address;
|
147
|
+
if (info.type) {
|
148
|
+
instance.type = info.type;
|
149
|
+
}
|
150
|
+
if (healthUrl) {
|
151
|
+
instance.health = healthUrl;
|
152
|
+
}
|
153
|
+
this.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
141
154
|
}
|
142
|
-
|
143
|
-
instance
|
155
|
+
else {
|
156
|
+
//If instance was not found - then we're receiving an externally started instance
|
157
|
+
instance = {
|
158
|
+
...info,
|
159
|
+
systemId,
|
160
|
+
instanceId,
|
161
|
+
status: types_1.InstanceStatus.STARTING,
|
162
|
+
startedAt: Date.now(),
|
163
|
+
desiredStatus: types_1.DesiredInstanceStatus.EXTERNAL,
|
164
|
+
owner: types_1.InstanceOwner.EXTERNAL,
|
165
|
+
health: healthUrl,
|
166
|
+
address,
|
167
|
+
};
|
168
|
+
this._instances.push(instance);
|
169
|
+
this.emitSystemEvent(systemId, EVENT_INSTANCE_CREATED, instance);
|
144
170
|
}
|
145
|
-
this.
|
146
|
-
|
147
|
-
|
148
|
-
//If instance was not found - then we're receiving an externally started instance
|
149
|
-
instance = {
|
150
|
-
...info,
|
151
|
-
systemId,
|
152
|
-
instanceId,
|
153
|
-
status: types_1.InstanceStatus.STARTING,
|
154
|
-
startedAt: Date.now(),
|
155
|
-
desiredStatus: types_1.DesiredInstanceStatus.EXTERNAL,
|
156
|
-
owner: types_1.InstanceOwner.EXTERNAL,
|
157
|
-
health: healthUrl,
|
158
|
-
address,
|
159
|
-
};
|
160
|
-
this._instances.push(instance);
|
161
|
-
this.emitSystemEvent(systemId, EVENT_INSTANCE_CREATED, instance);
|
162
|
-
}
|
163
|
-
this.save();
|
164
|
-
return instance;
|
171
|
+
this.save();
|
172
|
+
return instance;
|
173
|
+
});
|
165
174
|
}
|
166
175
|
getHealthUrl(info, address) {
|
167
176
|
let healthUrl = null;
|
@@ -175,15 +184,17 @@ class InstanceManager {
|
|
175
184
|
return healthUrl;
|
176
185
|
}
|
177
186
|
markAsStopped(systemId, instanceId) {
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
instance.status
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
+
return this.exclusive(systemId, instanceId, async () => {
|
188
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
189
|
+
const instance = lodash_1.default.find(this._instances, { systemId, instanceId });
|
190
|
+
if (instance && instance.owner === types_1.InstanceOwner.EXTERNAL && instance.status !== types_1.InstanceStatus.STOPPED) {
|
191
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
192
|
+
instance.pid = null;
|
193
|
+
instance.health = null;
|
194
|
+
this.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
195
|
+
this.save();
|
196
|
+
}
|
197
|
+
});
|
187
198
|
}
|
188
199
|
async startAllForPlan(systemId) {
|
189
200
|
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
@@ -212,54 +223,60 @@ class InstanceManager {
|
|
212
223
|
return settled.map((p) => (p.status === 'fulfilled' ? p.value : null)).filter((p) => !!p);
|
213
224
|
}
|
214
225
|
async stop(systemId, instanceId) {
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
instance.
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
226
|
+
return this.stopInner(systemId, instanceId, true);
|
227
|
+
}
|
228
|
+
async stopInner(systemId, instanceId, changeDesired = false) {
|
229
|
+
return this.exclusive(systemId, instanceId, async () => {
|
230
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
231
|
+
const instance = this.getInstance(systemId, instanceId);
|
232
|
+
if (!instance) {
|
233
|
+
return;
|
234
|
+
}
|
235
|
+
if (instance.status === types_1.InstanceStatus.STOPPED) {
|
236
|
+
return;
|
237
|
+
}
|
238
|
+
if (changeDesired &&
|
239
|
+
instance.desiredStatus !== types_1.DesiredInstanceStatus.EXTERNAL) {
|
240
|
+
instance.desiredStatus = types_1.DesiredInstanceStatus.STOP;
|
241
|
+
}
|
242
|
+
instance.status = types_1.InstanceStatus.STOPPING;
|
243
|
+
this.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
244
|
+
console.log('Stopping instance: %s::%s [desired: %s]', systemId, instanceId, instance.desiredStatus);
|
245
|
+
this.save();
|
246
|
+
try {
|
247
|
+
if (instance.type === 'docker') {
|
248
|
+
const containerName = (0, utils_1.getBlockInstanceContainerName)(instance.systemId, instance.instanceId);
|
249
|
+
const container = await containerManager_1.containerManager.getContainerByName(containerName);
|
250
|
+
if (container) {
|
251
|
+
try {
|
252
|
+
await container.stop();
|
253
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
254
|
+
this.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
255
|
+
this.save();
|
256
|
+
}
|
257
|
+
catch (e) {
|
258
|
+
console.error('Failed to stop container', e);
|
259
|
+
}
|
240
260
|
}
|
241
|
-
|
242
|
-
console.
|
261
|
+
else {
|
262
|
+
console.warn('Container not found', containerName);
|
243
263
|
}
|
264
|
+
return;
|
244
265
|
}
|
245
|
-
|
246
|
-
|
266
|
+
if (!instance.pid) {
|
267
|
+
instance.status = types_1.InstanceStatus.STOPPED;
|
268
|
+
this.save();
|
269
|
+
return;
|
247
270
|
}
|
248
|
-
|
249
|
-
}
|
250
|
-
if (!instance.pid) {
|
271
|
+
process.kill(instance.pid, 'SIGTERM');
|
251
272
|
instance.status = types_1.InstanceStatus.STOPPED;
|
273
|
+
this.emitSystemEvent(systemId, EVENT_STATUS_CHANGED, instance);
|
252
274
|
this.save();
|
253
|
-
return;
|
254
275
|
}
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
}
|
260
|
-
catch (e) {
|
261
|
-
console.error('Failed to stop process', e);
|
262
|
-
}
|
276
|
+
catch (e) {
|
277
|
+
console.error('Failed to stop process', e);
|
278
|
+
}
|
279
|
+
});
|
263
280
|
}
|
264
281
|
async stopAllForPlan(systemId) {
|
265
282
|
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
@@ -267,104 +284,111 @@ class InstanceManager {
|
|
267
284
|
return this.stopInstances(instancesForPlan);
|
268
285
|
}
|
269
286
|
async start(systemId, instanceId) {
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
const blockInstance = plan.spec && plan.spec.blocks ? lodash_1.default.find(plan.spec.blocks, { id: instanceId }) : null;
|
276
|
-
if (!blockInstance) {
|
277
|
-
throw new Error('Block instance not found: ' + instanceId);
|
278
|
-
}
|
279
|
-
const blockRef = (0, utils_1.normalizeKapetaUri)(blockInstance.block.ref);
|
280
|
-
const blockAsset = await assetManager_1.assetManager.getAsset(blockRef, true);
|
281
|
-
if (!blockAsset) {
|
282
|
-
throw new Error('Block not found: ' + blockRef);
|
283
|
-
}
|
284
|
-
const existingInstance = this.getInstance(systemId, instanceId);
|
285
|
-
if (existingInstance) {
|
286
|
-
if (existingInstance.status === types_1.InstanceStatus.READY) {
|
287
|
-
// Instance is already running
|
288
|
-
return existingInstance;
|
287
|
+
return this.exclusive(systemId, instanceId, async () => {
|
288
|
+
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
289
|
+
const plan = await assetManager_1.assetManager.getPlan(systemId, true);
|
290
|
+
if (!plan) {
|
291
|
+
throw new Error('Plan not found: ' + systemId);
|
289
292
|
}
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
return existingInstance;
|
293
|
+
const blockInstance = plan.spec && plan.spec.blocks ? lodash_1.default.find(plan.spec.blocks, { id: instanceId }) : null;
|
294
|
+
if (!blockInstance) {
|
295
|
+
throw new Error('Block instance not found: ' + instanceId);
|
294
296
|
}
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
297
|
+
const blockRef = (0, utils_1.normalizeKapetaUri)(blockInstance.block.ref);
|
298
|
+
const blockAsset = await assetManager_1.assetManager.getAsset(blockRef, true);
|
299
|
+
if (!blockAsset) {
|
300
|
+
throw new Error('Block not found: ' + blockRef);
|
299
301
|
}
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
// Check if the instance is already running - but after we've commmuicated the desired status
|
317
|
-
const currentStatus = await this.requestInstanceStatus(existingInstance);
|
318
|
-
if (currentStatus === types_1.InstanceStatus.READY) {
|
319
|
-
// Instance is already running
|
320
|
-
return existingInstance;
|
302
|
+
const existingInstance = this.getInstance(systemId, instanceId);
|
303
|
+
if (existingInstance) {
|
304
|
+
if (existingInstance.status === types_1.InstanceStatus.READY) {
|
305
|
+
// Instance is already running
|
306
|
+
return existingInstance;
|
307
|
+
}
|
308
|
+
if (existingInstance.desiredStatus === types_1.DesiredInstanceStatus.RUN &&
|
309
|
+
existingInstance.status === types_1.InstanceStatus.STARTING) {
|
310
|
+
// Internal instance is already starting - don't start it again
|
311
|
+
return existingInstance;
|
312
|
+
}
|
313
|
+
if (existingInstance.owner === types_1.InstanceOwner.EXTERNAL &&
|
314
|
+
existingInstance.status === types_1.InstanceStatus.STARTING) {
|
315
|
+
// External instance is already starting - don't start it again
|
316
|
+
return existingInstance;
|
317
|
+
}
|
321
318
|
}
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
319
|
+
let instance = {
|
320
|
+
systemId,
|
321
|
+
instanceId,
|
322
|
+
ref: blockRef,
|
323
|
+
name: blockAsset.data.metadata.name,
|
324
|
+
desiredStatus: types_1.DesiredInstanceStatus.RUN,
|
325
|
+
owner: types_1.InstanceOwner.INTERNAL,
|
326
|
+
type: existingInstance?.type ?? types_1.InstanceType.UNKNOWN,
|
327
|
+
status: types_1.InstanceStatus.STARTING,
|
328
|
+
startedAt: Date.now(),
|
329
|
+
};
|
330
|
+
console.log('Starting instance: %s::%s [desired: %s]', systemId, instanceId, instance.desiredStatus);
|
331
|
+
// Save the instance before starting it, so that we can track the status
|
332
|
+
await this.saveInternalInstance(instance);
|
333
|
+
if (existingInstance) {
|
334
|
+
// Check if the instance is already running - but after we've commmuicated the desired status
|
335
|
+
const currentStatus = await this.requestInstanceStatus(existingInstance);
|
336
|
+
if (currentStatus === types_1.InstanceStatus.READY) {
|
337
|
+
// Instance is already running
|
338
|
+
return existingInstance;
|
339
|
+
}
|
340
|
+
}
|
341
|
+
const instanceConfig = await configManager_1.configManager.getConfigForSection(systemId, instanceId);
|
342
|
+
const runner = new BlockInstanceRunner_1.BlockInstanceRunner(systemId);
|
343
|
+
const startTime = Date.now();
|
344
|
+
try {
|
345
|
+
const processInfo = await runner.start(blockRef, instanceId, instanceConfig);
|
346
|
+
instance.status = types_1.InstanceStatus.READY;
|
347
|
+
return this.saveInternalInstance({
|
348
|
+
...instance,
|
349
|
+
type: processInfo.type,
|
350
|
+
pid: processInfo.pid ?? -1,
|
351
|
+
health: null,
|
352
|
+
portType: processInfo.portType,
|
353
|
+
status: types_1.InstanceStatus.READY,
|
354
|
+
});
|
355
|
+
}
|
356
|
+
catch (e) {
|
357
|
+
console.warn('Failed to start instance', e);
|
358
|
+
const logs = [
|
359
|
+
{
|
360
|
+
source: 'stdout',
|
361
|
+
level: 'ERROR',
|
362
|
+
message: e.message,
|
363
|
+
time: Date.now(),
|
364
|
+
},
|
365
|
+
];
|
366
|
+
const out = await this.saveInternalInstance({
|
367
|
+
...instance,
|
368
|
+
type: types_1.InstanceType.LOCAL,
|
369
|
+
pid: null,
|
370
|
+
health: null,
|
371
|
+
portType: DEFAULT_HEALTH_PORT_TYPE,
|
372
|
+
status: types_1.InstanceStatus.FAILED,
|
373
|
+
});
|
374
|
+
this.emitInstanceEvent(systemId, instanceId, EVENT_INSTANCE_LOG, logs[0]);
|
375
|
+
this.emitInstanceEvent(systemId, blockInstance.id, EVENT_INSTANCE_EXITED, {
|
376
|
+
error: `Failed to start instance: ${e.message}`,
|
377
|
+
status: EVENT_INSTANCE_EXITED,
|
378
|
+
instanceId: blockInstance.id,
|
379
|
+
});
|
380
|
+
return out;
|
381
|
+
}
|
382
|
+
});
|
364
383
|
}
|
365
384
|
async restart(systemId, instanceId) {
|
366
385
|
systemId = (0, utils_1.normalizeKapetaUri)(systemId);
|
367
|
-
await this.
|
386
|
+
await this.stopInner(systemId, instanceId);
|
387
|
+
const existingInstance = this.getInstance(systemId, instanceId);
|
388
|
+
if (existingInstance?.desiredStatus === types_1.DesiredInstanceStatus.STOP) {
|
389
|
+
// Internal instance was marked as stopped - abort restart
|
390
|
+
return existingInstance;
|
391
|
+
}
|
368
392
|
return this.start(systemId, instanceId);
|
369
393
|
}
|
370
394
|
async stopAll() {
|
@@ -391,7 +415,7 @@ class InstanceManager {
|
|
391
415
|
const all = [...this._instances];
|
392
416
|
while (all.length > 0) {
|
393
417
|
// Check a few instances at a time - docker doesn't like too many concurrent requests
|
394
|
-
const chunk = all.splice(0,
|
418
|
+
const chunk = all.splice(0, 30);
|
395
419
|
const promises = chunk.map(async (instance) => {
|
396
420
|
if (!instance.systemId) {
|
397
421
|
return;
|
@@ -451,7 +475,7 @@ class InstanceManager {
|
|
451
475
|
[types_1.InstanceStatus.READY, types_1.InstanceStatus.STARTING, types_1.InstanceStatus.UNHEALTHY].includes(newStatus)) {
|
452
476
|
//If the instance is running but we want it to stop, stop it
|
453
477
|
try {
|
454
|
-
await this.
|
478
|
+
await this.stopInner(instance.systemId, instance.instanceId);
|
455
479
|
}
|
456
480
|
catch (e) {
|
457
481
|
console.warn('Failed to stop instance', instance.systemId, instance.instanceId, e);
|
@@ -2,11 +2,13 @@ import { InstanceInfo, LogEntry } from './types';
|
|
2
2
|
export declare class InstanceManager {
|
3
3
|
private _interval;
|
4
4
|
private readonly _instances;
|
5
|
+
private readonly instanceLocks;
|
5
6
|
constructor();
|
6
7
|
private checkInstancesLater;
|
7
8
|
getInstances(): InstanceInfo[];
|
8
9
|
getInstancesForPlan(systemId: string): InstanceInfo[];
|
9
10
|
getInstance(systemId: string, instanceId: string): InstanceInfo | undefined;
|
11
|
+
private exclusive;
|
10
12
|
getLogs(systemId: string, instanceId: string): Promise<LogEntry[]>;
|
11
13
|
saveInternalInstance(instance: InstanceInfo): Promise<InstanceInfo>;
|
12
14
|
/**
|
@@ -15,9 +17,10 @@ export declare class InstanceManager {
|
|
15
17
|
*/
|
16
18
|
registerInstanceFromSDK(systemId: string, instanceId: string, info: Omit<InstanceInfo, 'systemId' | 'instanceId'>): Promise<InstanceInfo | undefined>;
|
17
19
|
private getHealthUrl;
|
18
|
-
markAsStopped(systemId: string, instanceId: string): void
|
20
|
+
markAsStopped(systemId: string, instanceId: string): Promise<void>;
|
19
21
|
startAllForPlan(systemId: string): Promise<InstanceInfo[]>;
|
20
22
|
stop(systemId: string, instanceId: string): Promise<void>;
|
23
|
+
private stopInner;
|
21
24
|
stopAllForPlan(systemId: string): Promise<void>;
|
22
25
|
start(systemId: string, instanceId: string): Promise<InstanceInfo>;
|
23
26
|
restart(systemId: string, instanceId: string): Promise<InstanceInfo>;
|