Skip to content

Commit 7d913cd

Browse files
authored
Merge pull request #246 from Dexterp37/simplify_testlaunch
Remove the observer mechanism to wait for test tasks
2 parents 2d6b3ee + 9662bbb commit 7d913cd

File tree

2 files changed

+27
-140
lines changed

2 files changed

+27
-140
lines changed

glean/src/core/dispatcher.ts

Lines changed: 27 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
import { generateUUIDv4 } from "./utils.js";
6-
75
// The possible states a dispatcher instance can be in.
86
export const enum DispatcherState {
97
// The dispatcher has not been initialized yet.
@@ -29,36 +27,25 @@ const enum Commands {
2927
Stop,
3028
// The dispatcher should stop executing the queued tasks and clear the queue.
3129
Clear,
30+
// Exactly like a normal Task, but spawned for tests.
31+
TestTask,
3232
}
3333

3434
// A task the dispatcher knows how to execute.
3535
type Task = () => Promise<void>;
3636

3737
// An executable command.
3838
type Command = {
39-
testId?: string,
4039
task: Task,
4140
command: Commands.Task,
4241
} | {
43-
command: Exclude<Commands, Commands.Task>,
42+
resolver: (value: void | PromiseLike<void>) => void,
43+
task: Task,
44+
command: Commands.TestTask,
45+
} | {
46+
command: Exclude<Commands, Commands.Task | Commands.TestTask>,
4447
};
4548

46-
/**
47-
* An observer of the commands being executed by the dispatcher.
48-
*/
49-
class DispatcherObserver {
50-
constructor(private cb: (command: Command) => void) {}
51-
52-
/**
53-
* Updates an observer when the dispatcher finishes executing a command.
54-
*
55-
* @param command The command that was just executed by the dispatcher.
56-
*/
57-
update(command: Command): void {
58-
this.cb(command);
59-
}
60-
}
61-
6249
/**
6350
* A task dispatcher for async tasks.
6451
*
@@ -74,56 +61,11 @@ class Dispatcher {
7461
// This is `undefined` in case there is no ongoing execution of tasks.
7562
private currentJob?: Promise<void>;
7663

77-
// Observers that are notified about every executed command in this dispacther.
78-
//
79-
// This is private, because we only expect `testLaunch` to attach observers as of yet.
80-
private observers: DispatcherObserver[];
81-
8264
constructor(readonly maxPreInitQueueSize = 100) {
83-
this.observers = [];
8465
this.queue = [];
8566
this.state = DispatcherState.Uninitialized;
8667
}
8768

88-
/**
89-
* Attaches an observer that will be notified about state changes on the Dispatcher.
90-
*
91-
* # Note
92-
*
93-
* This is a private function because only the `testLaunch` function
94-
* is expected to watch the state of the Dispatcher as of yet.
95-
*
96-
* @param observer The observer to attach.
97-
*/
98-
private attachObserver(observer: DispatcherObserver): void {
99-
this.observers.push(observer);
100-
}
101-
102-
/**
103-
* Un-attaches an observer that will be notified about state changes on the Dispatcher.
104-
*
105-
* # Note
106-
*
107-
* This is a private function because only the `testLaunch` function
108-
* is expected to watch the state of the Dispatcher as of yet.
109-
*
110-
* @param observer The observer to attach.
111-
*/
112-
private unattachObserver(observer: DispatcherObserver): void {
113-
this.observers = this.observers.filter(curr => observer !== curr);
114-
}
115-
116-
/**
117-
* Notify any currently attached observer that a new command was executed.
118-
*
119-
* @param command The command to notify about
120-
*/
121-
private notifyObservers(command: Command): void {
122-
for (const observer of this.observers) {
123-
observer.update(command);
124-
}
125-
}
126-
12769
/**
12870
* Gets the oldest command added to the queue.
12971
*
@@ -155,16 +97,25 @@ class Dispatcher {
15597
switch(nextCommand.command) {
15698
case(Commands.Stop):
15799
this.state = DispatcherState.Stopped;
158-
this.notifyObservers(nextCommand);
159100
return;
160101
case(Commands.Clear):
102+
// Unblock test resolvers before clearing the queue.
103+
this.queue.forEach(c => {
104+
if (c.command === Commands.TestTask) {
105+
c.resolver();
106+
}
107+
});
108+
161109
this.queue = [];
162110
this.state = DispatcherState.Stopped;
163-
this.notifyObservers(nextCommand);
164111
return;
112+
case (Commands.TestTask):
113+
await this.executeTask(nextCommand.task);
114+
nextCommand.resolver();
115+
nextCommand = this.getNextCommand();
116+
continue;
165117
case(Commands.Task):
166118
await this.executeTask(nextCommand.task);
167-
this.notifyObservers(nextCommand);
168119
nextCommand = this.getNextCommand();
169120
}
170121
}
@@ -368,55 +319,19 @@ class Dispatcher {
368319
*
369320
* @returns A promise which only resolves once the task is done being executed
370321
* or is guaranteed to not be executed ever i.e. if the queue gets cleared.
371-
* This promise is rejected if the dispatcher takes more than 1s
372-
* to execute the current task i.e. if the dispatcher is uninitialized.
373322
*/
374323
testLaunch(task: Task): Promise<void> {
375-
const testId = generateUUIDv4();
376-
console.info("Launching a test task.", testId);
377-
378-
this.resume();
379-
const wasLaunched = this.launchInternal({
380-
testId,
381-
task,
382-
command: Commands.Task
383-
});
384-
385-
if (!wasLaunched) {
386-
return Promise.reject();
387-
}
388-
389-
// This promise will resolve:
390-
//
391-
// - If the dispatcher gets a Clear command;
392-
// - If a task with `testId` is executed;
393-
//
394-
// This promise will reject if:
395-
//
396-
// - If we wait for this task to be execute for more than 1s.
397-
// This is to attend to the case where the dispatcher is Stopped
398-
// and the task takes to long to be executed.
399-
return new Promise((resolve, reject) => {
400-
const observer = new DispatcherObserver((command: Command) => {
401-
const isCurrentTask = (command.command === Commands.Task && command.testId === testId);
402-
if (isCurrentTask || command.command === Commands.Clear) {
403-
this.unattachObserver(observer);
404-
clearTimeout(timeout);
405-
resolve();
406-
}
324+
return new Promise((resolver, reject) => {
325+
this.resume();
326+
const wasLaunched = this.launchInternal({
327+
resolver,
328+
task,
329+
command: Commands.TestTask
407330
});
408331

409-
const timeout = setTimeout(() => {
410-
console.error(
411-
`Test task ${testId} took to long to execute.`,
412-
"Please check if the dispatcher was initialized and is not stopped.",
413-
"Bailing out."
414-
);
415-
this.unattachObserver(observer);
332+
if (!wasLaunched) {
416333
reject();
417-
}, 1000);
418-
419-
this.attachObserver(observer);
334+
}
420335
});
421336
}
422337
}

glean/tests/core/dispatcher.spec.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,6 @@ describe("Dispatcher", function() {
340340
assert.strictEqual(dispatcher["state"], DispatcherState.Idle);
341341
});
342342

343-
it("testLaunch will reject in case the dispatcher is uninitialized for too long", async function () {
344-
dispatcher = new Dispatcher();
345-
try {
346-
await dispatcher.testLaunch(sampleTask);
347-
assert.ok(false);
348-
} catch {
349-
assert.ok(true);
350-
}
351-
});
352-
353343
it("testLaunch will not reject in case the dispatcher is uninitialized, but quickly initializes", async function () {
354344
dispatcher = new Dispatcher();
355345
const testLaunchedTask = dispatcher.testLaunch(sampleTask);
@@ -378,22 +368,4 @@ describe("Dispatcher", function() {
378368

379369
sinon.assert.callOrder(stub1, stub2, stub3);
380370
});
381-
382-
it("testLaunch observers are unattached after promise is resolved or rejected", async function() {
383-
dispatcher = new Dispatcher();
384-
385-
const willReject = dispatcher.testLaunch(sampleTask);
386-
assert.strictEqual(dispatcher["observers"].length, 1);
387-
try {
388-
await willReject;
389-
} catch {
390-
assert.strictEqual(dispatcher["observers"].length, 0);
391-
}
392-
393-
dispatcher.flushInit();
394-
const willNotReject = dispatcher.testLaunch(sampleTask);
395-
assert.strictEqual(dispatcher["observers"].length, 1);
396-
await willNotReject;
397-
assert.strictEqual(dispatcher["observers"].length, 0);
398-
});
399371
});

0 commit comments

Comments
 (0)