Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server(config, callback).start() causes node process to hang #2867

Open
joshuafodera opened this issue Nov 2, 2017 · 4 comments
Open

Server(config, callback).start() causes node process to hang #2867

joshuafodera opened this issue Nov 2, 2017 · 4 comments

Comments

@joshuafodera
Copy link

Expected behaviour

When a karma server has finished running, it should clean up so that node can exit, e.g.:

new Server(config, callback).start()

Actual behaviour

The node process hangs, and doesn't exit for upwards of a few minutes.

Environment Details

  • Latest Karma version (1.7.1/master branch):
  • Uses the repo karma.conf.js file: test/client/karma.conf.js with ChromeHeadless as the browser

Steps to reproduce the behaviour

Note: This isn't 100% repo (as sometimes writeBuffer is empty when karma server calls .disconnect on the socket, see below for more details).

  1. Create a karma test runner file, e.g.:
var Server = require('./lib/server')

new Server({
    configFile: "...karma-master/test/client/karma.conf.js",
    reporters: ['dots'],
    singleRun: true
}, (exitCode) => {
    console.log(`Exited with code: ${exitCode}`)
}).start()
  1. run from commandline: node runkarma.js
  2. re-run if repo doesn't hit

Cause

From debugging under node --inspect I see an engine.io socket stays alive preventing node from exiting.
Furthermore I see its caused by the writeBuffer containing messages preventing closeTransport from being called.
file: engine.io\lib\socket.js

Socket.prototype.close = function (discard) {
  if ('open' !== this.readyState) return;

  this.readyState = 'closing';

  if (this.writeBuffer.length) {
    this.once('drain', this.closeTransport.bind(this, discard));
    return;
  }

  this.closeTransport(discard);
};

Even more specifically its because the socket needs to cleanup the pingTimeout, which is done inside onClose which is called by closeTransport.

Note

Although the default behavior is to have the callback call process.exit, it doesn't work in our environment because:

  1. We use karma inside a gulp task, which then runs subsequent tasks, so we don't want to exit straight away
  2. We use "gulp watch" to run build/test tasks and this causes the subsequent watch tasks to stall
  3. I see in the main repo they use grunt to spawn a child process, however we use JavaScript to configure the karma config, so that won't be a clean solution, and
@johnjbarton
Copy link
Contributor

Can you create a (failing) test in this repo as a PR to illustrate the problem?

@joshuafodera
Copy link
Author

I can attempt to make one, its a little tricky because the bug is in karma not releasing the node instance, so the test would have to verify that the node instance exited (I'm not familiar with writing a test like that).

@filipesilva
Copy link
Contributor

Heya, I was faced with a similar problem today. As far as I can tell, it's because browser disconnection is setup on single run mode:
https://github.com/karma-runner/karma/blob/master/lib/server.js#L380-L383

But not on watch mode. So on watch mode even if you do something like

const karmaServer = new karma.Server({singleRun: false, configFile: '...'});
karmaServer.start();
karmaServer.emit('exit', () => { });

Karma would never really exit since the browsers are not disconnected.

I tried my hand at a PR for this in #2946.

@filipesilva
Copy link
Contributor

Actually, now that I read the original issue again, I'm not too sure my analysis and fix suit. The original issue is for singleRun mode only, whereas my problem is on watch mode only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants