Skip to content

Commit 9a5dc95

Browse files
author
Beatriz Rizental
authored
Merge pull request #799 from brizental/1732294-init-fail
Bug 1732294 - If initialization errors Glean doesn't do anything else
2 parents e52b3b2 + 7cf0b29 commit 9a5dc95

File tree

15 files changed

+101
-53
lines changed

15 files changed

+101
-53
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
* [#796](https://github.com/mozilla/glean.js/pull/796): Support setting the `app_channel` metric.
1010
- As described in ["Release channels"](https://mozilla.github.io/glean/book/reference/general/initializing.html?highlight=channel#release-channels).
11+
* [#799](https://github.com/mozilla/glean.js/pull/799): Make sure Glean does not do anything else in case initialization errors.
12+
- This may happen in case there is an error creating the databases. Mostly an issue on Qt/QML where we use a SQLite database which can throw errors on initialization.
13+
* [#799](https://github.com/mozilla/glean.js/pull/799): Provide stack traces when logging errors.
1114

1215
# v0.21.1 (2021-09-30)
1316

glean/src/cli.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,7 @@ async function run(args: string[]) {
238238
} catch (err) {
239239
log(
240240
LOG_TAG,
241-
[
242-
"Failed to setup the Glean build environment.\n",
243-
JSON.stringify(err)
244-
],
241+
["Failed to setup the Glean build environment.\n", err],
245242
LoggingLevel.Error
246243
);
247244
process.exit(1);

glean/src/core/dispatcher.ts

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ export const enum DispatcherState {
1212
//
1313
// When the dispatcher is in this state it will not enqueue
1414
// more than `maxPreInitQueueSize` tasks.
15-
Uninitialized,
15+
Uninitialized = "Uninitialized",
1616
// There are no commands queued and the dispatcher is idle.
17-
Idle,
17+
Idle = "Idle",
1818
// The dispatcher is currently processing queued tasks.
19-
Processing,
19+
Processing = "Processing",
2020
// The dispatcher is stopped, tasks queued will not be immediatelly processed.
21-
Stopped,
21+
Stopped = "Stopped",
2222
// The dispatcher is shutdown, attempting to queue tasks while in this state is a no-op.
2323
//
2424
// This state is irreversible.
25-
Shutdown,
25+
Shutdown = "Shutdown",
2626
}
2727

2828
// The possible commands to be processed by the dispatcher.
@@ -40,6 +40,12 @@ const enum Commands {
4040
//
4141
// Unless unavoidable, prefer using the normal `Task`.
4242
PersistentTask = "PersistentTask",
43+
// Same as the `Task` command, but only tasks passed to `flushInit` to be perfomed
44+
// as the first task ever are considered `InitTask`. This task is special because if
45+
// it fails, the dispatcher will not proceed executing any other tasks and will shutdown.
46+
//
47+
// This command is always followed by a concrete task for the dispatcher to execute.
48+
InitTask = "InitTask",
4349
// The dispatcher should stop executing the queued tasks.
4450
Stop = "Stop",
4551
// The dispatcher should stop executing the queued tasks and clear the queue.
@@ -52,17 +58,18 @@ const enum Commands {
5258

5359
// A task the dispatcher knows how to execute.
5460
type Task = () => Promise<void>;
61+
type TaskCommands = Commands.Task | Commands.TestTask | Commands.PersistentTask | Commands.InitTask;
5562

5663
// An executable command.
5764
type Command = {
5865
task: Task,
59-
command: Commands.Task | Commands.PersistentTask,
66+
command: Exclude<TaskCommands, Commands.TestTask>,
6067
} | {
6168
resolver: (value: void | PromiseLike<void>) => void,
6269
task: Task,
6370
command: Commands.TestTask,
6471
} | {
65-
command: Exclude<Commands, Commands.Task | Commands.TestTask | Commands.PersistentTask>,
72+
command: Exclude<Commands, TaskCommands>,
6673
};
6774

6875
/**
@@ -99,12 +106,15 @@ class Dispatcher {
99106
* Executes a task safely, catching any errors.
100107
*
101108
* @param task The task to execute.
109+
* @returns Whether or not the task was executed successfully.
102110
*/
103-
private async executeTask(task: Task): Promise<void> {
111+
private async executeTask(task: Task): Promise<boolean> {
104112
try {
105113
await task();
114+
return true;
106115
} catch(e) {
107-
log(this.logTag, ["Error executing task:", JSON.stringify(e)], LoggingLevel.Error);
116+
log(this.logTag, ["Error executing task:", e], LoggingLevel.Error);
117+
return false;
108118
}
109119
}
110120

@@ -142,18 +152,32 @@ class Dispatcher {
142152
this.queue = this.queue.filter(c =>
143153
[Commands.PersistentTask, Commands.Shutdown].includes(c.command)
144154
);
145-
nextCommand = this.getNextCommand();
146-
continue;
155+
break;
147156
case (Commands.TestTask):
148157
await this.executeTask(nextCommand.task);
149158
nextCommand.resolver();
150-
nextCommand = this.getNextCommand();
151-
continue;
159+
break;
160+
case(Commands.InitTask):
161+
const result = await this.executeTask(nextCommand.task);
162+
if (!result) {
163+
log(
164+
this.logTag,
165+
[
166+
"Error initializing dispatcher, won't execute anything further.",
167+
"There might be more error logs above."
168+
],
169+
LoggingLevel.Error
170+
);
171+
this.clear();
172+
void this.shutdown();
173+
}
174+
break;
152175
case(Commands.PersistentTask):
153176
case(Commands.Task):
154177
await this.executeTask(nextCommand.task);
155-
nextCommand = this.getNextCommand();
178+
break;
156179
}
180+
nextCommand = this.getNextCommand();
157181
}
158182
}
159183

@@ -277,6 +301,7 @@ class Dispatcher {
277301
* This is a no-op in case the dispatcher is not in an uninitialized state.
278302
*
279303
* @param task Optional task to execute before any of the tasks enqueued prior to init.
304+
* Note: if this task throws, the dispatcher will be shutdown and no other tasks will be executed.
280305
*/
281306
flushInit(task?: Task): void {
282307
if (this.state !== DispatcherState.Uninitialized) {
@@ -291,7 +316,7 @@ class Dispatcher {
291316
if (task) {
292317
this.launchInternal({
293318
task,
294-
command: Commands.Task
319+
command: Commands.InitTask
295320
}, true);
296321
}
297322

glean/src/core/error/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ export default class ErrorManager {
5959
* prepended to the message.
6060
* @param numErrors The number of errors of the same type to report.
6161
*/
62-
async record (
62+
async record(
6363
metric: MetricType,
6464
error: ErrorType,
65-
message: string,
65+
message: unknown,
6666
numErrors = 1
6767
): Promise<void> {
6868
const errorMetric = getErrorMetricForMetric(metric, error);
69-
log(createLogTag(metric), `${metric.baseIdentifier()}: ${message}`);
69+
log(createLogTag(metric), [`${metric.baseIdentifier()}:`, message]);
7070
if (numErrors > 0) {
7171
await CounterMetricType._private_addUndispatched(errorMetric, numErrors);
7272
} else {

glean/src/core/log.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ export enum LoggingLevel {
2929
*/
3030
export default function log(
3131
modulePath: string,
32-
message: string | string[],
32+
message: unknown | unknown[],
3333
level = LoggingLevel.Debug
3434
): void {
3535
const prefix = `(Glean.${modulePath})`;
36-
if (typeof message === "string") {
37-
console[level](prefix, message);
38-
} else {
36+
if (Array.isArray(message)) {
3937
console[level](prefix, ...message);
38+
} else {
39+
console[level](prefix, message);
4040
}
4141
}

glean/src/core/metrics/types/url.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ class UrlMetricType extends MetricType {
102102
await Context.metricsDatabase.record(this, metric);
103103
} catch (e) {
104104
if (e instanceof UrlMetricError) {
105-
await Context.errorManager.record(
106-
this,
107-
e.type,
108-
e.message
109-
);
105+
await Context.errorManager.record(this, e.type, e);
110106
}
111107
}
112108
});

glean/src/core/pings/maker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ export async function collectAndStorePing(identifier: string, ping: CommonPingDa
260260
`Error while attempting to modify ping payload for the "${ping.name}" ping using`,
261261
`the ${JSON.stringify(CoreEvents.afterPingCollection.registeredPluginIdentifier)} plugin.`,
262262
"Ping will not be submitted. See more logs below.\n\n",
263-
JSON.stringify(e)
263+
e
264264
],
265265
LoggingLevel.Error
266266
);

glean/src/core/storage/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function updateNestedObject(
8585
} catch(e) {
8686
log(
8787
LOG_TAG,
88-
["Error while transforming stored value. Ignoring old value.", JSON.stringify(e)],
88+
["Error while transforming stored value. Ignoring old value.", e],
8989
LoggingLevel.Error
9090
);
9191
target[finalKey] = transformFn(undefined);

glean/src/core/upload/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -272,14 +272,7 @@ class PingUploader implements PingsDatabaseObserver {
272272
finalPing.headers
273273
);
274274
} catch(e) {
275-
log(
276-
LOG_TAG,
277-
[
278-
"Error trying to build ping request:",
279-
(e as Error).message
280-
],
281-
LoggingLevel.Warn
282-
);
275+
log(LOG_TAG, [ "Error trying to build ping request:", e ], LoggingLevel.Warn);
283276
// An unrecoverable failure will make sure the offending ping is removed from the queue and
284277
// deleted from the database, which is what we want here.
285278
return new UploadResult(UploadResultStatus.RecoverableFailure);

glean/src/platform/qt/storage.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ class QMLStore implements Store {
132132
} catch(e) {
133133
log(
134134
this.logTag,
135-
["Error while attempting to access LocalStorage.\n", JSON.stringify(e)],
135+
["Error while attempting to access LocalStorage.\n", e],
136136
LoggingLevel.Debug
137137
);
138138
} finally {
@@ -155,7 +155,7 @@ class QMLStore implements Store {
155155
} catch (e) {
156156
log(
157157
this.logTag,
158-
[`Error executing LocalStorage query: ${query}.\n`, JSON.stringify(e)],
158+
[`Error executing LocalStorage query: ${query}.\n`, e],
159159
LoggingLevel.Debug
160160
);
161161
reject();
@@ -190,10 +190,7 @@ class QMLStore implements Store {
190190
try {
191191
return getValueFromNestedObject(obj, index);
192192
} catch(e) {
193-
log(this.logTag, [
194-
"Error getting value from database.",
195-
JSON.stringify((e as Error).message)
196-
]);
193+
log(this.logTag, ["Error getting value from database.", e]);
197194
}
198195
}
199196

0 commit comments

Comments
 (0)