Skip to content

Commit c0095f9

Browse files
committed
Merge branch 'release-v0.18.0' into release
2 parents 14af0bf + 4151594 commit c0095f9

File tree

26 files changed

+593
-736
lines changed

26 files changed

+593
-736
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ jobs:
132132
source venv/bin/activate
133133
pip install -r requirements.txt
134134
glean_parser translate metrics.yaml pings.yaml -f javascript -o generated \
135-
--option platform=qt --option version="0.17"
135+
--option platform=qt --option version="0.18"
136136
137137
sudo apt-get install xvfb
138138
xvfb-run python main.py &> qml.log &

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Unreleased changes
22

3-
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.17.0...main)
3+
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.18.0...main)
4+
5+
# v0.18.0 (2021-07-20)
6+
7+
[Full changelog](https://github.com/mozilla/glean.js/compare/v0.17.0...v0.18.0)
8+
9+
* [#542](https://github.com/mozilla/glean.js/pull/542): Implement `shutdown` API.
410

511
# v0.17.0 (2021-07-16)
612

glean/package-lock.json

Lines changed: 130 additions & 410 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glean/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mozilla/glean",
3-
"version": "0.17.0",
3+
"version": "0.18.0",
44
"description": "An implementation of the Glean SDK, a modern cross-platform telemetry client, for JavaScript environments.",
55
"type": "module",
66
"sideEffects": "false",

glean/src/core/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const GLEAN_SCHEMA_VERSION = 1;
88
//
99
// PACKAGE_VERSION is defined as a global by webpack,
1010
// we need a default here for testing when the app is not build with webpack.
11-
export const GLEAN_VERSION = "0.17.0";
11+
export const GLEAN_VERSION = "0.18.0";
1212

1313
// The name of a "ping" that will include Glean ping_info metrics,
1414
// such as ping sequence numbers.

glean/src/core/dispatcher.ts

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ export const enum DispatcherState {
1919
Processing,
2020
// The dispatcher is stopped, tasks queued will not be immediatelly processed.
2121
Stopped,
22+
// The dispatcher is shutdown, attempting to queue tasks while in this state is a no-op.
23+
//
24+
// This state is irreversible.
25+
Shutdown,
2226
}
2327

2428
// The possible commands to be processed by the dispatcher.
@@ -31,6 +35,8 @@ const enum Commands {
3135
Stop,
3236
// The dispatcher should stop executing the queued tasks and clear the queue.
3337
Clear,
38+
// The dispatcher will clear the queue and go into the Shutdown state.
39+
Shutdown,
3440
// Exactly like a normal Task, but spawned for tests.
3541
TestTask,
3642
}
@@ -65,7 +71,7 @@ class Dispatcher {
6571
// This is `undefined` in case there is no ongoing execution of tasks.
6672
private currentJob?: Promise<void>;
6773

68-
constructor(readonly maxPreInitQueueSize = 100) {
74+
constructor(readonly maxPreInitQueueSize = 100, readonly logTag = LOG_TAG) {
6975
this.queue = [];
7076
this.state = DispatcherState.Uninitialized;
7177
}
@@ -88,7 +94,7 @@ class Dispatcher {
8894
try {
8995
await task();
9096
} catch(e) {
91-
log(LOG_TAG, ["Error executing task:", e], LoggingLevel.Error);
97+
log(this.logTag, ["Error executing task:", e], LoggingLevel.Error);
9298
}
9399
}
94100

@@ -102,6 +108,7 @@ class Dispatcher {
102108
case(Commands.Stop):
103109
this.state = DispatcherState.Stopped;
104110
return;
111+
case(Commands.Shutdown):
105112
case(Commands.Clear):
106113
// Unblock test resolvers before clearing the queue.
107114
this.queue.forEach(c => {
@@ -111,7 +118,12 @@ class Dispatcher {
111118
});
112119

113120
this.queue = [];
114-
this.state = DispatcherState.Stopped;
121+
if (nextCommand.command === Commands.Clear) {
122+
this.state = DispatcherState.Stopped;
123+
} else {
124+
this.state = DispatcherState.Shutdown;
125+
}
126+
115127
return;
116128
case (Commands.TestTask):
117129
await this.executeTask(nextCommand.task);
@@ -149,7 +161,7 @@ class Dispatcher {
149161
})
150162
.catch(error => {
151163
log(
152-
LOG_TAG,
164+
this.logTag,
153165
[
154166
"IMPOSSIBLE: Something went wrong while the dispatcher was executing the tasks queue.",
155167
error
@@ -175,10 +187,19 @@ class Dispatcher {
175187
* @returns Wheter or not the task was queued.
176188
*/
177189
private launchInternal(command: Command, priorityTask = false): boolean {
190+
if (this.state === DispatcherState.Shutdown) {
191+
log(
192+
this.logTag,
193+
"Attempted to enqueue a new task but the dispatcher is shutdown. Ignoring.",
194+
LoggingLevel.Warn
195+
);
196+
return false;
197+
}
198+
178199
if (!priorityTask && this.state === DispatcherState.Uninitialized) {
179200
if (this.queue.length >= this.maxPreInitQueueSize) {
180201
log(
181-
LOG_TAG,
202+
this.logTag,
182203
"Unable to enqueue task, pre init queue is full.",
183204
LoggingLevel.Warn
184205
);
@@ -226,7 +247,7 @@ class Dispatcher {
226247
flushInit(task?: Task): void {
227248
if (this.state !== DispatcherState.Uninitialized) {
228249
log(
229-
LOG_TAG,
250+
this.logTag,
230251
"Attempted to initialize the Dispatcher, but it is already initialized. Ignoring.",
231252
LoggingLevel.Warn
232253
);
@@ -286,6 +307,27 @@ class Dispatcher {
286307
}
287308
}
288309

310+
/**
311+
* Shutsdown the dispatcher.
312+
*
313+
* 1. Executes all tasks launched prior to this one.
314+
* 2. Clears the queue of any tasks launched after this one.
315+
* 3. Puts the dispatcher in the `Shutdown` state.
316+
*
317+
* # Note
318+
*
319+
* - This is a command like any other, if the dispatcher is uninitialized
320+
* it will get executed when the dispatcher is initialized.
321+
* - If the dispatcher is stopped, it is resumed and all pending tasks are executed.
322+
*
323+
* @returns A promise which resolves once shutdown is complete.
324+
*/
325+
shutdown(): Promise<void> {
326+
this.launchInternal({ command: Commands.Shutdown });
327+
this.resume();
328+
return this.currentJob || Promise.resolve();
329+
}
330+
289331
/**
290332
* Test-Only API**
291333
*
@@ -330,6 +372,11 @@ class Dispatcher {
330372
*
331373
* This is important in order not to hang forever in case the dispatcher is stopped.
332374
*
375+
* # Errors
376+
*
377+
* This function will reject in case the task is not launched.
378+
* Make sure the dispatcher is initialized or is not shutdown in these cases.
379+
*
333380
* @param task The task to launch.
334381
* @returns A promise which only resolves once the task is done being executed
335382
* or is guaranteed to not be executed ever i.e. if the queue gets cleared.

glean/src/core/glean.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class Glean {
115115
*/
116116
private static async clearMetrics(): Promise<void> {
117117
// Stop ongoing upload jobs and clear pending pings queue.
118-
await Glean.pingUploader.clearPendingPingsQueue();
118+
Glean.pingUploader.clearPendingPingsQueue();
119119

120120
// There is only one metric that we want to survive after clearing all
121121
// metrics: first_run_date. Here, we store its value
@@ -281,11 +281,6 @@ class Glean {
281281
}
282282

283283
await Context.pingsDatabase.scanPendingPings();
284-
285-
// Even though this returns a promise, there is no need to block on it returning.
286-
//
287-
// On the contrary we _want_ the uploading tasks to be executed async.
288-
void Glean.pingUploader.triggerUpload();
289284
});
290285
}
291286

@@ -418,6 +413,27 @@ class Glean {
418413
});
419414
}
420415

416+
/**
417+
* Finishes executing all pending tasks
418+
* and shuts down both Glean's dispatcher and the ping uploader.
419+
*
420+
* # Important
421+
*
422+
* This is irreversible.
423+
* Only a restart will return Glean back to an idle state.
424+
*
425+
* @returns A promise which resolves once the shutdown is complete.
426+
*/
427+
static async shutdown(): Promise<void> {
428+
// Order here matters!
429+
//
430+
// The main dispatcher needs to be shut down first,
431+
// because some of its tasks may enqueue new tasks on the ping uploader dispatcher
432+
// and we want these uploading tasks to also be executed prior to complete shutdown.
433+
await Context.dispatcher.shutdown();
434+
await Glean.pingUploader.shutdown();
435+
}
436+
421437
/**
422438
* Sets the current environment.
423439
*
@@ -491,11 +507,13 @@ class Glean {
491507
// Deregister all plugins
492508
testResetEvents();
493509

494-
// Stop ongoing jobs and clear pending pings queue.
510+
// Await ongoing jobs and clear pending pings queue.
495511
if (Glean.pingUploader) {
512+
await Glean.pingUploader.testBlockOnPingsQueue();
513+
496514
// The first time tests run, before Glean is initialized, we are
497515
// not guaranteed to have an uploader. Account for this.
498-
await Glean.pingUploader.clearPendingPingsQueue();
516+
Glean.pingUploader.clearPendingPingsQueue();
499517
}
500518
}
501519

0 commit comments

Comments
 (0)