From 33bac0d810c58d6115114162c5e28df15f716bdb Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Wed, 20 Apr 2022 12:32:51 -0400 Subject: [PATCH 1/6] correct worker process close sequence --- main/externalData/balances/controller.ts | 39 +++++++++++++----------- main/index.js | 5 +++ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/main/externalData/balances/controller.ts b/main/externalData/balances/controller.ts index fab00c705..d41d73e6d 100644 --- a/main/externalData/balances/controller.ts +++ b/main/externalData/balances/controller.ts @@ -28,9 +28,9 @@ export default class BalancesWorkerController extends EventEmitter { constructor () { super() - + const workerArgs = process.env.NODE_ENV === 'development' ? ['--inspect=127.0.0.1:9230'] : [] - this.worker = fork(path.resolve(__dirname, 'worker.js'), workerArgs) + this.worker = fork(path.resolve(__dirname, 'worker.js'), [], { execArgv: workerArgs }) log.info('created balances worker, pid:', this.worker.pid) @@ -56,38 +56,39 @@ export default class BalancesWorkerController extends EventEmitter { } }) - this.worker.on('exit', code => { - const exitCode = code || this.worker.signalCode - log.warn(`balances worker exited with code ${exitCode}, pid: ${this.worker.pid}`) - this.close() + this.worker.on('close', (code, signal) => { + // emitted after exit or error and when all stdio streams are closed + log.warn(`balances worker exited with code ${code}, signal: ${signal}, pid: ${this.worker.pid}`) + this.worker.removeAllListeners() + + this.emit('close') + this.removeAllListeners() }) this.worker.on('disconnect', () => { log.warn(`balances worker disconnected`) - this.close() + this.stopWorker() }) this.worker.on('error', err => { log.warn(`balances worker sent error, pid: ${this.worker.pid}`, err) - this.close() + this.stopWorker() }) } - close () { + private stopWorker () { if (this.heartbeat) { clearInterval(this.heartbeat) this.heartbeat = undefined } - this.worker.removeAllListeners() - - const exitCode = this.worker.exitCode - const killed = this.worker.killed || this.worker.kill('SIGTERM') + this.worker.kill('SIGTERM') + } - log.info(`worker controller closed, exitCode: ${exitCode}, killed by controller: ${killed}`) + close () { + log.info(`closing worker controller`) - this.emit('close') - this.removeAllListeners() + this.stopWorker() } isRunning () { @@ -111,7 +112,7 @@ export default class BalancesWorkerController extends EventEmitter { log.debug(`sending command ${command} to worker`) try { - if (!this.worker.connected || !this.worker.channel) { + if (!this.isWorkerReachable()) { log.error(`attempted to send command "${command}" to worker but worker cannot be reached!`) return } @@ -125,4 +126,8 @@ export default class BalancesWorkerController extends EventEmitter { private sendHeartbeat () { this.sendCommandToWorker('heartbeat') } + + private isWorkerReachable () { + return this.worker.connected && this.worker.channel && this.worker.listenerCount('error') > 0 + } } diff --git a/main/index.js b/main/index.js index d17703fbe..c86338e2e 100644 --- a/main/index.js +++ b/main/index.js @@ -99,6 +99,11 @@ log.info('Electron: v' + process.versions.electron) log.info('Node: v' + process.versions.node) process.on('uncaughtException', (e) => { + if (e.code === 'EPIPE') { + log.error('uncaught EPIPE error', e) + return + } + if (e.code === 'EADDRINUSE') { dialog.showErrorBox('Frame is already running', 'Frame is already running or another application is using port 1248.') } else { From 38b4fe5ef50161e37a84c815fd661c6c707fae64 Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Wed, 20 Apr 2022 12:36:45 -0400 Subject: [PATCH 2/6] make sure worker in running to fix race condition --- main/externalData/balances/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/main/externalData/balances/index.ts b/main/externalData/balances/index.ts index 5df659d3e..10f855f8c 100644 --- a/main/externalData/balances/index.ts +++ b/main/externalData/balances/index.ts @@ -95,7 +95,9 @@ export default function (store: Store) { updateActiveBalances(address) }, 0) - scan = setTimeout(() => scanForAddress(), 20 * 1000) + scan = setTimeout(() => { + if (workerController?.isRunning()) scanForAddress() + }, 20 * 1000) } runWhenReady(() => scanForAddress()) From e0ce0108d743a2bb7f3470e7a1a8cfb35f79ee89 Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Thu, 21 Apr 2022 08:58:33 -0400 Subject: [PATCH 3/6] add ms to worker logging --- main/externalData/balances/worker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/externalData/balances/worker.ts b/main/externalData/balances/worker.ts index ed40abff9..c41545ab4 100644 --- a/main/externalData/balances/worker.ts +++ b/main/externalData/balances/worker.ts @@ -2,7 +2,7 @@ import log from 'electron-log' import ethProvider from 'eth-provider' -log.transports.console.format = '[scanWorker] {h}:{i}:{s} {text}' +log.transports.console.format = '[scanWorker] {h}:{i}:{s}.{ms} {text}' log.transports.console.level = process.env.LOG_WORKER ? 'debug' : 'info' log.transports.file.level = ['development', 'test'].includes(process.env.NODE_ENV) ? false : 'verbose' From 602ee4d5c521139ff0c9386882cbc499ad90a928 Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Thu, 21 Apr 2022 10:40:28 -0400 Subject: [PATCH 4/6] add renderer process error reporting --- app/index.js | 3 +++ main/index.js | 2 ++ 2 files changed, 5 insertions(+) diff --git a/app/index.js b/app/index.js index 9be9f68a9..e13a288ec 100644 --- a/app/index.js +++ b/app/index.js @@ -1,3 +1,4 @@ +import * as Sentry from '@sentry/electron' import React from 'react' import ReactDOM from 'react-dom' import Restore from 'react-restore' @@ -9,6 +10,8 @@ import _store from './store' import './flex' +Sentry.init({ dsn: 'https://7b09a85b26924609bef5882387e2c4dc@o1204372.ingest.sentry.io/6331069' }) + // window.removeAllAccountsAndSigners = () => link.send('tray:removeAllAccountsAndSigners') document.addEventListener('dragover', e => e.preventDefault()) diff --git a/main/index.js b/main/index.js index c86338e2e..66dda7b74 100644 --- a/main/index.js +++ b/main/index.js @@ -50,6 +50,8 @@ function getCrashReportFields () { } Sentry.init({ + // only use IPC from renderer process, not HTTP + ipcMode: Sentry.IPCMode.Classic, dsn: 'https://7b09a85b26924609bef5882387e2c4dc@o1204372.ingest.sentry.io/6331069', beforeSend: (evt) => { return { From b976c56ab79cd588564e67bffea890faa1d73df1 Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Thu, 21 Apr 2022 10:45:51 -0400 Subject: [PATCH 5/6] capture uncaught exceptions --- main/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main/index.js b/main/index.js index 66dda7b74..9b13dc1d3 100644 --- a/main/index.js +++ b/main/index.js @@ -101,6 +101,8 @@ log.info('Electron: v' + process.versions.electron) log.info('Node: v' + process.versions.node) process.on('uncaughtException', (e) => { + Sentry.captureException(e) + if (e.code === 'EPIPE') { log.error('uncaught EPIPE error', e) return From 545cff3706f0666eb787869feb1f9bc7d7e31551 Mon Sep 17 00:00:00 2001 From: Matt Holtzman Date: Thu, 21 Apr 2022 10:47:34 -0400 Subject: [PATCH 6/6] move some stuff around --- main/externalData/balances/controller.ts | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/main/externalData/balances/controller.ts b/main/externalData/balances/controller.ts index d41d73e6d..064d62b81 100644 --- a/main/externalData/balances/controller.ts +++ b/main/externalData/balances/controller.ts @@ -76,15 +76,6 @@ export default class BalancesWorkerController extends EventEmitter { }) } - private stopWorker () { - if (this.heartbeat) { - clearInterval(this.heartbeat) - this.heartbeat = undefined - } - - this.worker.kill('SIGTERM') - } - close () { log.info(`closing worker controller`) @@ -107,6 +98,20 @@ export default class BalancesWorkerController extends EventEmitter { this.sendCommandToWorker('tokenBalanceScan', [address, tokens, chains]) } + // private + private stopWorker () { + if (this.heartbeat) { + clearInterval(this.heartbeat) + this.heartbeat = undefined + } + + this.worker.kill('SIGTERM') + } + + private isWorkerReachable () { + return this.worker.connected && this.worker.channel && this.worker.listenerCount('error') > 0 + } + // sending messages private sendCommandToWorker (command: string, args: any[] = []) { log.debug(`sending command ${command} to worker`) @@ -126,8 +131,4 @@ export default class BalancesWorkerController extends EventEmitter { private sendHeartbeat () { this.sendCommandToWorker('heartbeat') } - - private isWorkerReachable () { - return this.worker.connected && this.worker.channel && this.worker.listenerCount('error') > 0 - } }