Skip to content

Commit 1ec564e

Browse files
committed
chore(compas): minimize dangling promises
1 parent b0daa14 commit 1ec564e

File tree

6 files changed

+84
-29
lines changed

6 files changed

+84
-29
lines changed

packages/compas/src/main/development/integrations/cache-cleanup.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ export class CacheCleanupIntegration extends BaseIntegration {
1515
this.state.cache.cachesCleaned = true;
1616

1717
if (!hasPreviouslyCleaned) {
18-
return await this.state.emitCacheUpdated();
18+
await this.cleanup();
1919
}
2020
}
2121

2222
async onConfigUpdated() {
2323
await super.onConfigUpdated();
2424

25-
await this.cleanup();
25+
this.state.runTask("CachesCleanup", this.cleanup());
2626
}
2727

2828
async cleanup() {

packages/compas/src/main/development/integrations/file-watcher.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ export class FileWatcherIntegration extends BaseIntegration {
9393
);
9494
}
9595

96-
// Dangling promise!
9796
boundEmitFileChange(events.map((it) => it.path));
9897
},
9998
FileWatcherIntegration.DEFAULT_WATCH_OPTIONS,

packages/compas/src/main/development/integrations/inferred-actions.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ export class InferredActionsIntegration extends BaseIntegration {
1515
await super.init();
1616

1717
if (isNil(this.state.cache.availableActions)) {
18-
await this.resolveAvailableActions();
18+
this.state.runTask(
19+
"inferredActionsResolve",
20+
this.resolveAvailableActions(),
21+
);
1922
}
2023

2124
this.state.fileChangeRegister.push({
@@ -27,12 +30,18 @@ export class InferredActionsIntegration extends BaseIntegration {
2730

2831
async onCacheUpdated() {
2932
await super.onCacheUpdated();
30-
await this.resolveAvailableActions();
33+
this.state.runTask(
34+
"inferredActionsResolve",
35+
this.resolveAvailableActions(),
36+
);
3137
}
3238

3339
async onFileChanged(paths) {
3440
await super.onFileChanged(paths);
35-
await this.resolveAvailableActions();
41+
this.state.runTask(
42+
"inferredActionsResolve",
43+
this.resolveAvailableActions(),
44+
);
3645
}
3746

3847
async resolveAvailableActions() {

packages/compas/src/main/development/integrations/package-manager.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ export class PackageManagerIntegration extends BaseIntegration {
1616
if (!this.state.cache.packageManager) {
1717
await this.resolve();
1818

19-
// TODO: do we want to start with an 'await this.execute();'
20-
// May want to do that as background task.
19+
this.state.runTask("packageManagerExecute", this.execute());
2120
}
2221

2322
this.state.fileChangeRegister.push({
@@ -62,7 +61,7 @@ export class PackageManagerIntegration extends BaseIntegration {
6261
}
6362

6463
if (installCommand) {
65-
return this.execute();
64+
this.state.runTask("packageManagerExecute", this.execute());
6665
}
6766
}
6867

packages/compas/src/main/development/state.js

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export class State {
8484
};
8585
}
8686

87-
// ==== generic ====
87+
// ==== generic lifecycle ====
8888

8989
async init() {
9090
debugTimeStart(`State#init`);
@@ -108,11 +108,15 @@ export class State {
108108
new ConfigLoaderIntegration(this),
109109
new RootDirectoriesIntegration(this),
110110
new CacheCleanupIntegration(this),
111-
new InferredActionsIntegration(this),
112111
new ActionsIntegration(this),
112+
113+
// Try to keep the above list minimal.
114+
113115
new PackageManagerIntegration(this),
116+
new InferredActionsIntegration(this),
114117

115-
// Should be the last integration, since it will
118+
// Should be the last integration, since it will process file changes since the
119+
// last snapshot.
116120
new FileWatcherIntegration(this),
117121
];
118122

@@ -208,6 +212,48 @@ export class State {
208212
}
209213
}
210214

215+
// ==== background tasks ====
216+
217+
/**
218+
*
219+
* @param {string} name
220+
* @param {Promise|(() => Promise<any>)} task
221+
* @param {{
222+
* exitOnFailure?: boolean,
223+
* }} [options]
224+
* @returns {*}
225+
*/
226+
runTask(name, task, { exitOnFailure } = {}) {
227+
if (typeof task === "function") {
228+
return this.runTask(name, task, { exitOnFailure });
229+
}
230+
231+
if (!(task instanceof Promise)) {
232+
throw AppError.serverError({
233+
message: "Received a task that isn't a promise.",
234+
name,
235+
task,
236+
});
237+
}
238+
239+
const _self = this;
240+
241+
debugPrint(`State#runTask :: ${name} :: registered`);
242+
243+
task
244+
.then(() => {
245+
debugPrint(`State#runTask :: ${name} :: fulfilled`);
246+
})
247+
.catch((e) => {
248+
debugPrint(`State#runTask :: ${name} :: rejected`);
249+
debugPrint(AppError.format(e));
250+
251+
if (exitOnFailure) {
252+
_self.runTask("State#exit", _self.exit());
253+
}
254+
});
255+
}
256+
211257
// ==== integrations ====
212258

213259
/**
@@ -249,7 +295,8 @@ export class State {
249295
return;
250296
}
251297

252-
// Rename a few keypress for easier matching and shorter shortcuts, we may want to expand this setup later.
298+
// Rename a few keypress for easier matching and shorter shortcuts, we may want to
299+
// expand this setup later.
253300
if (key.name === "escape") {
254301
key.name = "esc";
255302
}
@@ -271,21 +318,21 @@ export class State {
271318
emitFileChange(paths) {
272319
debugPrint(`State#emitFileChange :: ${JSON.stringify(paths)}}`);
273320

274-
for (const integration of this.fileChangeRegister) {
275-
if (micromatch.some(paths, integration.glob)) {
321+
for (const registerItem of this.fileChangeRegister) {
322+
if (micromatch.some(paths, registerItem.glob)) {
276323
debugPrint(
277-
`State#emitFileChange :: Matched ${integration.glob} for ${integration.integration.name} debouncing with ${integration.debounceDelay}.`,
324+
`State#emitFileChange :: Matched ${registerItem.glob} for ${registerItem.integration.name} debouncing with ${registerItem.debounceDelay}.`,
278325
);
279326

280-
if (integration.existingTimeout) {
281-
integration.existingTimeout.refresh();
327+
if (registerItem.existingTimeout) {
328+
registerItem.existingTimeout.refresh();
282329
} else {
283-
integration.existingTimeout = setTimeout(() => {
284-
// We don't ever clear the timeout, since refreshing will restart the timeout.
285-
286-
// Dangling promise!
287-
integration.integration.onFileChanged(paths);
288-
}, integration.debounceDelay);
330+
registerItem.existingTimeout = setTimeout(() => {
331+
registerItem.integration.state.runTask(
332+
"Integration#onFileChaged",
333+
registerItem.integration.onFileChanged(paths),
334+
);
335+
}, registerItem.debounceDelay);
289336
}
290337
}
291338
}

packages/compas/src/main/development/tui.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ export function tuiInit(state) {
1313

1414
// Exit listeners
1515
process.on("SIGABRT", () => {
16-
state.exit();
16+
state.runTask("SIGABRT", state.exit(), { exitOnFailure: true });
1717
});
1818
process.on("SIGINT", () => {
19-
state.exit();
19+
state.runTask("SIGINT", state.exit(), { exitOnFailure: true });
2020
});
2121
process.on("beforeExit", () => {
22-
state.exit();
22+
state.runTask("beforeExit", state.exit());
2323
});
2424

2525
process.stdout.on("resize", () => state.resizeScreen());
@@ -33,11 +33,12 @@ export function tuiInit(state) {
3333
process.stdin.on("keypress", (char, raw) => {
3434
if (raw.name === "c" && raw.ctrl) {
3535
// Ctrl + C
36-
state.exit();
36+
state.runTask("Ctrl + C", state.exit(), { exitOnFailure: true });
37+
3738
return;
3839
}
3940

40-
state.emitKeypress(raw);
41+
state.runTask("tuiEmitKeyPress", state.emitKeypress(raw));
4142
});
4243
}
4344

0 commit comments

Comments
 (0)