diff --git a/lib/server.js b/lib/server.js index c61748a40..c883d1384 100644 --- a/lib/server.js +++ b/lib/server.js @@ -123,6 +123,13 @@ class Server extends KarmaEventEmitter { BundleUtils.bundleResourceIfNotExist('context/main.js', 'static/context.js') ]) this._boundServer = await NetUtils.bindAvailablePort(config.port, config.listenAddress) + this._boundServer.on('connection', (socket) => { + // Attach an error handler to avoid UncaughtException errors. + socket.on('error', (err) => { + // Errors on this socket are retried, ignore them + this.log.debug('Ignoring error on webserver connection: ' + err) + }) + }) config.port = this._boundServer.address().port this._injector.invoke(this._start, this) } catch (err) { @@ -228,6 +235,10 @@ class Server extends KarmaEventEmitter { socket.on('complete', (data, ack) => ack()) + socket.on('error', (err) => { + this.log.debug('karma server socket error: ' + err) + }) + socket.on('register', (info) => { let newBrowser = info.id ? (capturedBrowsers.getById(info.id) || singleRunBrowsers.getById(info.id)) : null @@ -372,14 +383,19 @@ class Server extends KarmaEventEmitter { processWrapper.on('SIGINT', () => disconnectBrowsers(process.exitCode)) processWrapper.on('SIGTERM', disconnectBrowsers) - processWrapper.on('uncaughtException', (error) => { - this.log.error(error) + const reportError = (error) => { + process.emit('infrastructure_error', error) disconnectBrowsers(1) - }) + } processWrapper.on('unhandledRejection', (error) => { - this.log.error(error) - disconnectBrowsers(1) + this.log.error('UnhandledRejection') + reportError(error) + }) + + processWrapper.on('uncaughtException', (error) => { + this.log.error('UncaughtException') + reportError(error) }) } diff --git a/test/unit/server.spec.js b/test/unit/server.spec.js index b24ef5f6e..e2f6ab027 100644 --- a/test/unit/server.spec.js +++ b/test/unit/server.spec.js @@ -91,7 +91,7 @@ describe('server', () => { } mockBoundServer = { - on: sinon.spy((event, callback) => callback && callback()), + on: sinon.spy((event, callback) => callback && callback(mockServerSocket)), listen: sinon.spy((port, listenAddress, callback) => callback && callback()), close: sinon.spy((callback) => callback && callback()), address: () => { return { port: 9876 } } @@ -148,6 +148,7 @@ describe('server', () => { server.start().then(() => { expect(NetUtils.bindAvailablePort).to.have.been.calledWith(9876, '127.0.0.1') expect(mockBoundServer.address).to.have.been.called + expect(typeof mockSocketEventListeners.get('error')).to.be.equal('function') done() }) })