flightdeck 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flightdeck.bin.js +45 -19
- package/dist/lib.d.ts +4 -3
- package/dist/lib.js +44 -17
- package/package.json +7 -7
- package/src/flightdeck.bin.ts +1 -2
- package/src/flightdeck.lib.ts +60 -22
package/dist/flightdeck.bin.js
CHANGED
|
@@ -198,8 +198,7 @@ class FlightDeck {
|
|
|
198
198
|
}
|
|
199
199
|
this.getLatestRelease();
|
|
200
200
|
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
201
|
-
this.
|
|
202
|
-
this.stopAllServices();
|
|
201
|
+
this.tryUpdate();
|
|
203
202
|
return;
|
|
204
203
|
}
|
|
205
204
|
for (const entry of toEntries(this.services)) {
|
|
@@ -236,13 +235,40 @@ class FlightDeck {
|
|
|
236
235
|
this.logger.info(`Server started on port ${port}`);
|
|
237
236
|
});
|
|
238
237
|
}
|
|
239
|
-
this.startAllServices()
|
|
238
|
+
this.startAllServices().then(() => {
|
|
239
|
+
this.logger.info(`All services started.`);
|
|
240
|
+
}).catch((thrown) => {
|
|
241
|
+
if (thrown instanceof Error) {
|
|
242
|
+
this.logger.error(`Failed to start all services:`, thrown.message);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
tryUpdate() {
|
|
247
|
+
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
248
|
+
this.logger.info(`All services are ready to update.`);
|
|
249
|
+
this.stopAllServices().then(() => {
|
|
250
|
+
this.logger.info(`All services stopped; starting up fresh...`);
|
|
251
|
+
this.startAllServices().then(() => {
|
|
252
|
+
this.logger.info(`All services started; we're back online.`);
|
|
253
|
+
}).catch((thrown) => {
|
|
254
|
+
if (thrown instanceof Error) {
|
|
255
|
+
this.logger.error(`Failed to start all services:`, thrown.message);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}).catch((thrown) => {
|
|
259
|
+
if (thrown instanceof Error) {
|
|
260
|
+
this.logger.error(`Failed to stop all services:`, thrown.message);
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
240
264
|
}
|
|
241
265
|
startAllServices() {
|
|
242
266
|
this.logger.info(`Starting all services...`);
|
|
267
|
+
this.servicesShouldRestart = true;
|
|
243
268
|
for (const [serviceName] of toEntries(this.services)) {
|
|
244
269
|
this.startService(serviceName);
|
|
245
270
|
}
|
|
271
|
+
return this.live;
|
|
246
272
|
}
|
|
247
273
|
startService(serviceName) {
|
|
248
274
|
this.logger.info(`Starting service ${this.options.packageName}::${serviceName}, try ${this.safety}/2...`);
|
|
@@ -270,10 +296,7 @@ class FlightDeck {
|
|
|
270
296
|
this.services[serviceName].on(`readyToUpdate`, () => {
|
|
271
297
|
this.serviceLoggers[serviceName].info(`Ready to update.`);
|
|
272
298
|
this.servicesReadyToUpdate[serviceName] = true;
|
|
273
|
-
|
|
274
|
-
this.logger.info(`All services are ready to update.`);
|
|
275
|
-
this.stopAllServices();
|
|
276
|
-
}
|
|
299
|
+
this.tryUpdate();
|
|
277
300
|
});
|
|
278
301
|
this.services[serviceName].on(`alive`, () => {
|
|
279
302
|
this.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve());
|
|
@@ -285,7 +308,7 @@ class FlightDeck {
|
|
|
285
308
|
}
|
|
286
309
|
this.dead.use(Promise.all(this.servicesDead));
|
|
287
310
|
});
|
|
288
|
-
this.services[serviceName].process.
|
|
311
|
+
this.services[serviceName].process.once(`close`, (exitCode) => {
|
|
289
312
|
this.serviceLoggers[serviceName].info(`Exited with code ${exitCode}`);
|
|
290
313
|
this.services[serviceName] = null;
|
|
291
314
|
if (!this.servicesShouldRestart) {
|
|
@@ -346,16 +369,25 @@ class FlightDeck {
|
|
|
346
369
|
}
|
|
347
370
|
stopAllServices() {
|
|
348
371
|
this.logger.info(`Stopping all services...`);
|
|
372
|
+
this.servicesShouldRestart = false;
|
|
349
373
|
for (const [serviceName] of toEntries(this.services)) {
|
|
350
374
|
this.stopService(serviceName);
|
|
351
375
|
}
|
|
376
|
+
return this.dead;
|
|
352
377
|
}
|
|
353
378
|
stopService(serviceName) {
|
|
354
|
-
|
|
379
|
+
const service = this.services[serviceName];
|
|
380
|
+
if (service) {
|
|
355
381
|
this.serviceLoggers[serviceName].info(`Stopping service...`);
|
|
356
|
-
this.
|
|
357
|
-
|
|
358
|
-
|
|
382
|
+
this.servicesDead[this.serviceIdx[serviceName]].use(new Promise((pass) => {
|
|
383
|
+
service.emit(`timeToStop`);
|
|
384
|
+
service.process.once(`close`, (exitCode) => {
|
|
385
|
+
this.logger.info(`\uD83D\uDEEC service ${serviceName} exited with code ${exitCode}`);
|
|
386
|
+
this.services[serviceName] = null;
|
|
387
|
+
pass();
|
|
388
|
+
});
|
|
389
|
+
}));
|
|
390
|
+
this.dead.use(Promise.all(this.servicesDead));
|
|
359
391
|
this.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {
|
|
360
392
|
});
|
|
361
393
|
if (this.live.done) {
|
|
@@ -367,11 +399,6 @@ class FlightDeck {
|
|
|
367
399
|
this.serviceLoggers[serviceName].error(`Tried to stop service, but it wasn't running.`);
|
|
368
400
|
}
|
|
369
401
|
}
|
|
370
|
-
shutdown() {
|
|
371
|
-
this.logger.info(`Shutting down...`);
|
|
372
|
-
this.servicesShouldRestart = false;
|
|
373
|
-
this.stopAllServices();
|
|
374
|
-
}
|
|
375
402
|
}
|
|
376
403
|
|
|
377
404
|
// src/flightdeck.bin.ts
|
|
@@ -463,8 +490,7 @@ switch (inputs.case) {
|
|
|
463
490
|
default: {
|
|
464
491
|
const flightDeck = new FlightDeck(inputs.opts);
|
|
465
492
|
process.on(`close`, async () => {
|
|
466
|
-
flightDeck.stopAllServices();
|
|
467
|
-
await flightDeck.dead;
|
|
493
|
+
await flightDeck.stopAllServices();
|
|
468
494
|
});
|
|
469
495
|
}
|
|
470
496
|
}
|
package/dist/lib.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ declare class FlightDeck<S extends string = string> {
|
|
|
23
23
|
protected webhookServer: Server;
|
|
24
24
|
protected services: {
|
|
25
25
|
[service in S]: ChildSocket<{
|
|
26
|
+
timeToStop: [];
|
|
26
27
|
updatesReady: [];
|
|
27
28
|
}, {
|
|
28
29
|
readyToUpdate: [];
|
|
@@ -50,13 +51,13 @@ declare class FlightDeck<S extends string = string> {
|
|
|
50
51
|
protected restartTimes: number[];
|
|
51
52
|
protected persistentStateDir: string;
|
|
52
53
|
constructor(options: FlightDeckOptions<S>);
|
|
53
|
-
protected
|
|
54
|
+
protected tryUpdate(): void;
|
|
55
|
+
protected startAllServices(): Future<unknown>;
|
|
54
56
|
protected startService(serviceName: S): void;
|
|
55
57
|
protected applyUpdate(): void;
|
|
56
58
|
protected getLatestRelease(): void;
|
|
57
|
-
stopAllServices():
|
|
59
|
+
stopAllServices(): Future<unknown>;
|
|
58
60
|
stopService(serviceName: S): void;
|
|
59
|
-
shutdown(): void;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
type AlertOptions = {
|
package/dist/lib.js
CHANGED
|
@@ -202,8 +202,7 @@ class FlightDeck {
|
|
|
202
202
|
}
|
|
203
203
|
this.getLatestRelease();
|
|
204
204
|
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
205
|
-
this.
|
|
206
|
-
this.stopAllServices();
|
|
205
|
+
this.tryUpdate();
|
|
207
206
|
return;
|
|
208
207
|
}
|
|
209
208
|
for (const entry of toEntries(this.services)) {
|
|
@@ -240,13 +239,40 @@ class FlightDeck {
|
|
|
240
239
|
this.logger.info(`Server started on port ${port}`);
|
|
241
240
|
});
|
|
242
241
|
}
|
|
243
|
-
this.startAllServices()
|
|
242
|
+
this.startAllServices().then(() => {
|
|
243
|
+
this.logger.info(`All services started.`);
|
|
244
|
+
}).catch((thrown) => {
|
|
245
|
+
if (thrown instanceof Error) {
|
|
246
|
+
this.logger.error(`Failed to start all services:`, thrown.message);
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
tryUpdate() {
|
|
251
|
+
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
252
|
+
this.logger.info(`All services are ready to update.`);
|
|
253
|
+
this.stopAllServices().then(() => {
|
|
254
|
+
this.logger.info(`All services stopped; starting up fresh...`);
|
|
255
|
+
this.startAllServices().then(() => {
|
|
256
|
+
this.logger.info(`All services started; we're back online.`);
|
|
257
|
+
}).catch((thrown) => {
|
|
258
|
+
if (thrown instanceof Error) {
|
|
259
|
+
this.logger.error(`Failed to start all services:`, thrown.message);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}).catch((thrown) => {
|
|
263
|
+
if (thrown instanceof Error) {
|
|
264
|
+
this.logger.error(`Failed to stop all services:`, thrown.message);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
244
268
|
}
|
|
245
269
|
startAllServices() {
|
|
246
270
|
this.logger.info(`Starting all services...`);
|
|
271
|
+
this.servicesShouldRestart = true;
|
|
247
272
|
for (const [serviceName] of toEntries(this.services)) {
|
|
248
273
|
this.startService(serviceName);
|
|
249
274
|
}
|
|
275
|
+
return this.live;
|
|
250
276
|
}
|
|
251
277
|
startService(serviceName) {
|
|
252
278
|
this.logger.info(`Starting service ${this.options.packageName}::${serviceName}, try ${this.safety}/2...`);
|
|
@@ -274,10 +300,7 @@ class FlightDeck {
|
|
|
274
300
|
this.services[serviceName].on(`readyToUpdate`, () => {
|
|
275
301
|
this.serviceLoggers[serviceName].info(`Ready to update.`);
|
|
276
302
|
this.servicesReadyToUpdate[serviceName] = true;
|
|
277
|
-
|
|
278
|
-
this.logger.info(`All services are ready to update.`);
|
|
279
|
-
this.stopAllServices();
|
|
280
|
-
}
|
|
303
|
+
this.tryUpdate();
|
|
281
304
|
});
|
|
282
305
|
this.services[serviceName].on(`alive`, () => {
|
|
283
306
|
this.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve());
|
|
@@ -289,7 +312,7 @@ class FlightDeck {
|
|
|
289
312
|
}
|
|
290
313
|
this.dead.use(Promise.all(this.servicesDead));
|
|
291
314
|
});
|
|
292
|
-
this.services[serviceName].process.
|
|
315
|
+
this.services[serviceName].process.once(`close`, (exitCode) => {
|
|
293
316
|
this.serviceLoggers[serviceName].info(`Exited with code ${exitCode}`);
|
|
294
317
|
this.services[serviceName] = null;
|
|
295
318
|
if (!this.servicesShouldRestart) {
|
|
@@ -350,16 +373,25 @@ class FlightDeck {
|
|
|
350
373
|
}
|
|
351
374
|
stopAllServices() {
|
|
352
375
|
this.logger.info(`Stopping all services...`);
|
|
376
|
+
this.servicesShouldRestart = false;
|
|
353
377
|
for (const [serviceName] of toEntries(this.services)) {
|
|
354
378
|
this.stopService(serviceName);
|
|
355
379
|
}
|
|
380
|
+
return this.dead;
|
|
356
381
|
}
|
|
357
382
|
stopService(serviceName) {
|
|
358
|
-
|
|
383
|
+
const service = this.services[serviceName];
|
|
384
|
+
if (service) {
|
|
359
385
|
this.serviceLoggers[serviceName].info(`Stopping service...`);
|
|
360
|
-
this.
|
|
361
|
-
|
|
362
|
-
|
|
386
|
+
this.servicesDead[this.serviceIdx[serviceName]].use(new Promise((pass) => {
|
|
387
|
+
service.emit(`timeToStop`);
|
|
388
|
+
service.process.once(`close`, (exitCode) => {
|
|
389
|
+
this.logger.info(`\uD83D\uDEEC service ${serviceName} exited with code ${exitCode}`);
|
|
390
|
+
this.services[serviceName] = null;
|
|
391
|
+
pass();
|
|
392
|
+
});
|
|
393
|
+
}));
|
|
394
|
+
this.dead.use(Promise.all(this.servicesDead));
|
|
363
395
|
this.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {
|
|
364
396
|
});
|
|
365
397
|
if (this.live.done) {
|
|
@@ -371,11 +403,6 @@ class FlightDeck {
|
|
|
371
403
|
this.serviceLoggers[serviceName].error(`Tried to stop service, but it wasn't running.`);
|
|
372
404
|
}
|
|
373
405
|
}
|
|
374
|
-
shutdown() {
|
|
375
|
-
this.logger.info(`Shutting down...`);
|
|
376
|
-
this.servicesShouldRestart = false;
|
|
377
|
-
this.stopAllServices();
|
|
378
|
-
}
|
|
379
406
|
}
|
|
380
407
|
// src/klaxon.lib.ts
|
|
381
408
|
var exports_klaxon_lib = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flightdeck",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jeremy Banka",
|
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@t3-oss/env-core": "0.11.1",
|
|
25
25
|
"zod": "3.23.8",
|
|
26
|
-
"atom.io": "0.30.
|
|
26
|
+
"atom.io": "0.30.2",
|
|
27
27
|
"comline": "0.1.6"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/node": "22.
|
|
30
|
+
"@types/node": "22.9.0",
|
|
31
31
|
"@types/tmp": "0.2.6",
|
|
32
|
-
"bun-types": "1.1.
|
|
33
|
-
"concurrently": "9.0
|
|
32
|
+
"bun-types": "1.1.34",
|
|
33
|
+
"concurrently": "9.1.0",
|
|
34
34
|
"rimraf": "6.0.1",
|
|
35
35
|
"tmp": "0.2.3",
|
|
36
|
-
"tsup": "8.3.
|
|
37
|
-
"vitest": "2.1.
|
|
36
|
+
"tsup": "8.3.5",
|
|
37
|
+
"vitest": "2.1.4"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "rimraf dist && concurrently \"bun:build:*\" && concurrently \"bun:schema:*\"",
|
package/src/flightdeck.bin.ts
CHANGED
package/src/flightdeck.lib.ts
CHANGED
|
@@ -28,7 +28,7 @@ export class FlightDeck<S extends string = string> {
|
|
|
28
28
|
protected webhookServer: Server
|
|
29
29
|
protected services: {
|
|
30
30
|
[service in S]: ChildSocket<
|
|
31
|
-
{ updatesReady: [] },
|
|
31
|
+
{ timeToStop: []; updatesReady: [] },
|
|
32
32
|
{ readyToUpdate: []; alive: [] }
|
|
33
33
|
> | null
|
|
34
34
|
}
|
|
@@ -174,8 +174,7 @@ export class FlightDeck<S extends string = string> {
|
|
|
174
174
|
([, isReady]) => isReady,
|
|
175
175
|
)
|
|
176
176
|
) {
|
|
177
|
-
this.
|
|
178
|
-
this.stopAllServices()
|
|
177
|
+
this.tryUpdate()
|
|
179
178
|
return
|
|
180
179
|
}
|
|
181
180
|
for (const entry of toEntries(this.services)) {
|
|
@@ -216,13 +215,50 @@ export class FlightDeck<S extends string = string> {
|
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
this.startAllServices()
|
|
218
|
+
.then(() => {
|
|
219
|
+
this.logger.info(`All services started.`)
|
|
220
|
+
})
|
|
221
|
+
.catch((thrown) => {
|
|
222
|
+
if (thrown instanceof Error) {
|
|
223
|
+
this.logger.error(`Failed to start all services:`, thrown.message)
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
protected tryUpdate(): void {
|
|
229
|
+
if (toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)) {
|
|
230
|
+
this.logger.info(`All services are ready to update.`)
|
|
231
|
+
this.stopAllServices()
|
|
232
|
+
.then(() => {
|
|
233
|
+
this.logger.info(`All services stopped; starting up fresh...`)
|
|
234
|
+
this.startAllServices()
|
|
235
|
+
.then(() => {
|
|
236
|
+
this.logger.info(`All services started; we're back online.`)
|
|
237
|
+
})
|
|
238
|
+
.catch((thrown) => {
|
|
239
|
+
if (thrown instanceof Error) {
|
|
240
|
+
this.logger.error(
|
|
241
|
+
`Failed to start all services:`,
|
|
242
|
+
thrown.message,
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
.catch((thrown) => {
|
|
248
|
+
if (thrown instanceof Error) {
|
|
249
|
+
this.logger.error(`Failed to stop all services:`, thrown.message)
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
}
|
|
219
253
|
}
|
|
220
254
|
|
|
221
|
-
protected startAllServices():
|
|
255
|
+
protected startAllServices(): Future<unknown> {
|
|
222
256
|
this.logger.info(`Starting all services...`)
|
|
257
|
+
this.servicesShouldRestart = true
|
|
223
258
|
for (const [serviceName] of toEntries(this.services)) {
|
|
224
259
|
this.startService(serviceName)
|
|
225
260
|
}
|
|
261
|
+
return this.live
|
|
226
262
|
}
|
|
227
263
|
|
|
228
264
|
protected startService(serviceName: S): void {
|
|
@@ -261,12 +297,7 @@ export class FlightDeck<S extends string = string> {
|
|
|
261
297
|
this.services[serviceName].on(`readyToUpdate`, () => {
|
|
262
298
|
this.serviceLoggers[serviceName].info(`Ready to update.`)
|
|
263
299
|
this.servicesReadyToUpdate[serviceName] = true
|
|
264
|
-
|
|
265
|
-
toEntries(this.servicesReadyToUpdate).every(([, isReady]) => isReady)
|
|
266
|
-
) {
|
|
267
|
-
this.logger.info(`All services are ready to update.`)
|
|
268
|
-
this.stopAllServices()
|
|
269
|
-
}
|
|
300
|
+
this.tryUpdate()
|
|
270
301
|
})
|
|
271
302
|
this.services[serviceName].on(`alive`, () => {
|
|
272
303
|
this.servicesLive[this.serviceIdx[serviceName]].use(Promise.resolve())
|
|
@@ -276,7 +307,7 @@ export class FlightDeck<S extends string = string> {
|
|
|
276
307
|
}
|
|
277
308
|
this.dead.use(Promise.all(this.servicesDead))
|
|
278
309
|
})
|
|
279
|
-
this.services[serviceName].process.
|
|
310
|
+
this.services[serviceName].process.once(`close`, (exitCode) => {
|
|
280
311
|
this.serviceLoggers[serviceName].info(`Exited with code ${exitCode}`)
|
|
281
312
|
this.services[serviceName] = null
|
|
282
313
|
if (!this.servicesShouldRestart) {
|
|
@@ -345,19 +376,32 @@ export class FlightDeck<S extends string = string> {
|
|
|
345
376
|
}
|
|
346
377
|
}
|
|
347
378
|
|
|
348
|
-
public stopAllServices():
|
|
379
|
+
public stopAllServices(): Future<unknown> {
|
|
349
380
|
this.logger.info(`Stopping all services...`)
|
|
381
|
+
this.servicesShouldRestart = false
|
|
350
382
|
for (const [serviceName] of toEntries(this.services)) {
|
|
351
383
|
this.stopService(serviceName)
|
|
352
384
|
}
|
|
385
|
+
return this.dead
|
|
353
386
|
}
|
|
354
387
|
|
|
355
388
|
public stopService(serviceName: S): void {
|
|
356
|
-
|
|
389
|
+
const service = this.services[serviceName]
|
|
390
|
+
if (service) {
|
|
357
391
|
this.serviceLoggers[serviceName].info(`Stopping service...`)
|
|
358
|
-
this.
|
|
359
|
-
|
|
360
|
-
|
|
392
|
+
this.servicesDead[this.serviceIdx[serviceName]].use(
|
|
393
|
+
new Promise((pass) => {
|
|
394
|
+
service.emit(`timeToStop`)
|
|
395
|
+
service.process.once(`close`, (exitCode) => {
|
|
396
|
+
this.logger.info(
|
|
397
|
+
`🛬 service ${serviceName} exited with code ${exitCode}`,
|
|
398
|
+
)
|
|
399
|
+
this.services[serviceName] = null
|
|
400
|
+
pass()
|
|
401
|
+
})
|
|
402
|
+
}),
|
|
403
|
+
)
|
|
404
|
+
this.dead.use(Promise.all(this.servicesDead))
|
|
361
405
|
this.servicesLive[this.serviceIdx[serviceName]] = new Future(() => {})
|
|
362
406
|
if (this.live.done) {
|
|
363
407
|
this.live = new Future(() => {})
|
|
@@ -369,10 +413,4 @@ export class FlightDeck<S extends string = string> {
|
|
|
369
413
|
)
|
|
370
414
|
}
|
|
371
415
|
}
|
|
372
|
-
|
|
373
|
-
public shutdown(): void {
|
|
374
|
-
this.logger.info(`Shutting down...`)
|
|
375
|
-
this.servicesShouldRestart = false
|
|
376
|
-
this.stopAllServices()
|
|
377
|
-
}
|
|
378
416
|
}
|