Skip to content

Commit d3ffa91

Browse files
committed
Make server retry logic more reliable & transparent
1 parent 274bbfa commit d3ffa91

File tree

1 file changed

+37
-7
lines changed

1 file changed

+37
-7
lines changed

src/index.ts

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function reportError(error: Error | string) {
1313
import { spawn, exec, ChildProcess } from 'child_process';
1414
import * as os from 'os';
1515
import * as path from 'path';
16-
import { app, BrowserWindow, shell, Menu } from 'electron';
16+
import { app, BrowserWindow, shell, Menu, Notification } from 'electron';
1717

1818
import * as windowStateKeeper from 'electron-window-state';
1919

@@ -165,6 +165,11 @@ app.on('web-contents-created', (_event, contents) => {
165165
});
166166
});
167167

168+
function showNotification(title: string, body: string) {
169+
const notification = new Notification({ title, body, icon: path.join(__dirname, 'src', 'icon.png') });
170+
notification.show();
171+
}
172+
168173
async function startServer(retries = 2) {
169174
const binName = isWindows ? 'httptoolkit-server.cmd' : 'httptoolkit-server';
170175
const serverBinPath = path.join(__dirname, '..', 'httptoolkit-server', 'bin', binName);
@@ -184,29 +189,55 @@ async function startServer(retries = 2) {
184189
Sentry.addBreadcrumb({ category: 'server-stdout', message: data.toString('utf8'), level: <any> 'info' });
185190
});
186191

192+
let lastError: string | undefined = undefined;
187193
server.stderr.on('data', (data) => {
188-
Sentry.addBreadcrumb({ category: 'server-stderr', message: data.toString('utf8'), level: <any> 'warning' });
194+
const errorOutput = data.toString('utf8');
195+
Sentry.addBreadcrumb({ category: 'server-stderr', message: errorOutput, level: <any> 'warning' });
196+
197+
// Remember the last '*Error:' line we saw.
198+
lastError = errorOutput
199+
.split('\n')
200+
.filter((line: string) => line.match(/^\w*Error:/))
201+
.slice(-1)[0];
189202
});
190203

204+
const serverStartTime = Date.now();
205+
191206
const serverShutdown: Promise<void> = new Promise<Error | number | null>((resolve) => {
192207
server!.once('error', resolve);
193208
server!.once('exit', resolve);
194209
}).then((errorOrCode) => {
195210
if (serverKilled) return;
196211

197212
// The server should never shutdown unless the whole process is finished, so this is bad.
213+
const serverRunTime = Date.now() - serverStartTime;
214+
215+
let error: Error;
216+
217+
if (errorOrCode && typeof errorOrCode !== 'number') {
218+
error = errorOrCode;
219+
} else if (lastError) {
220+
error = new Error(`Server crashed with '${lastError}' (${errorOrCode})`);
221+
} else {
222+
error = new Error(`Server shutdown unexpectedly with code ${errorOrCode}`);
223+
}
198224

199-
const error = errorOrCode && typeof errorOrCode !== 'number' ?
200-
errorOrCode : new Error(`Server shutdown unexpectedly with code ${errorOrCode}.`);
225+
Sentry.addBreadcrumb({ category: 'server-exit', message: error.message, level: <any> 'error', data: { serverRunTime } });
226+
reportError(error);
201227

202-
if (retries > 0) {
203-
Sentry.addBreadcrumb({ category: 'server-exit', message: error.message, level: <any> 'error' });
228+
showNotification(
229+
'HTTP Toolkit crashed',
230+
`${error.message}. Please file an issue at github.com/httptoolkit/feedback.`
231+
);
204232

233+
// Retry limited times, but not for near-immediate failures.
234+
if (retries > 0 && serverRunTime > 5000) {
205235
// This will break the app, so refresh it
206236
if (mainWindow) mainWindow.reload();
207237
return startServer(retries - 1);
208238
}
209239

240+
// If we've run out of retries, throw (kill the app entirely)
210241
throw error;
211242
});
212243

@@ -223,7 +254,6 @@ if (require('electron-squirrel-startup')) {
223254
setTimeout(() => app.quit(), 500);
224255
} else {
225256
startServer().catch((err) => {
226-
reportError(err);
227257
console.error('Failed to start server, exiting.', err);
228258

229259
// Hide immediately, shutdown entirely after a brief pause for Sentry

0 commit comments

Comments
 (0)