webdriverio-boneyard / wdio-selenium-standalone-service

WebdriverIO v4 service to start & stop Selenium Standalone http://webdriver.io
MIT License
54 stars 28 forks source link

Session is not cleaning up all chromedriver processes #28

Open Gary-Osteen-Q2 opened 7 years ago

Gary-Osteen-Q2 commented 7 years ago

For versions 0.0.8 and 0.0.9, the test run does not shut down all 2.31-x64-chromedriver processes when finished. This does not happen when using firefox/geckodriver. When running more than one spec, multiple 2.31-x64-chromedriver processes get started but one will always remain per test run. I have tested this with 1 and 2 specs in the wdio conf.

Current workaround that works for me:

Add this to your wdio.config.js file.

afterSession: async function(){
    // workaround to make sure the chromedriver shuts down
    await browser.end().pause(1000);
},
after: async function(){
    // workaround to make sure the chromedriver shuts down
    await browser.pause(1000);
}
Gary-Osteen-Q2 commented 7 years ago

Further testing shows this does not happen when you manually start the standalone jar before running the tests.

joshden commented 7 years ago

I am seeing the same issue with multiple specs. As a workaround, I set the Chrome capability maxInstances to 1 to run the specs serially.

// wdio.conf.js
capabilities: [{
    // maxInstances can get overwritten per capability. So if you have an in-house Selenium
    // grid with only 5 firefox instances available you can make sure that not more than
    // 5 instances get started at a time.
    maxInstances: 1,
    browserName: 'chrome'
}],
Gary-Osteen-Q2 commented 7 years ago

Interesting if that works. This might be acceptable for smaller projects, but when you have a large collection, this would slow things down a lot if you are use to running 3 or more parallel instances.. That said, it might work for me for now, but won't be a sustainable workaround for long.

dangmai commented 7 years ago

Yup I'm running into this same issue as well, and setting maxInstances to 1 is at best a temporary work around.

FlippieCoetser commented 6 years ago

The workaround does not work for me. With each manual run of a set of tests, a new 2.31-x64-chromedriver process is created, even if I have the maxInstances set to 1.

FlippieCoetser commented 6 years ago

A workaround, which is not ideal but works for me, is to use shelljs to run a kill command, in the afterSession hook:

shell.exec('taskkill /FI "IMAGENAME eq 2.33-x64-chromedriver" /F')
rgustavsson commented 6 years ago

I'm using chromedriver 2.33-x64 through the `services: [ 'selenium-standalone' ] and the chromedriver instances do not stop themselves even if I set maxInstances to 1.

    maxInstances: 1,
    capabilities: [
      {
        maxInstances: 1,
        browserName: 'chrome'
      }

in my package.json:

    "webdriverio": "4.9.9",
    "wdio-selenium-standalone-service": "0.0.9",
christian-bromann commented 6 years ago

@rgustavsson so it's more an issue of the selenium-standalone service?

rgustavsson commented 6 years ago

@christian-bromann not sure.

@Gary-Osteen-Q2 mentioned:

Further testing shows this does not happen when you manually start the standalone jar before running the tests.

So I was assuming that it works when running the selenium-standalone service manually.

mike-suggitt commented 6 years ago

Bumping this. Any thoughts on what might be causing this yet? It's causing issues on our build servers as we get up to 100+ running instances of chromedriver! Plus it means we can't clean down the workspace between builds because of the same said running process.

Miladinho commented 6 years ago

I have experienced this on both Chrome and Firefox with its geckodriver

goatsy commented 6 years ago

Me too. On Windows and Mac. Really problematic.

ashmind commented 6 years ago

Tried to do some research on this (on Windows).

It seems that selenium-standalone starts java.exe and then something (Java?) starts 2.33-x64-chromedriver. When kill is called (see below), it kills java.exe but not 2.33-x64-chromedriver: https://github.com/webdriverio/wdio-selenium-standalone-service/blob/ccb38ec3edd1b2bf80d3592ba3412e6bf0075179/lib/launcher.js#L36-L38

Seems like an issue in selenium-standalone, however I can't find anyone reporting it there, so maybe something specific in how it is invoked?

phil-lgr commented 6 years ago

image

Experiencing as well on windows 10:

 "wdio": "1.0.3",
    "wdio-browserstack-service": "0.1.14",
    "wdio-jasmine-framework": "0.3.2",
    "wdio-junit-reporter": "0.3.1",
    "wdio-selenium-standalone-service": "0.0.9",
phil-lgr commented 6 years ago

@ashmind did you find anything new? Debugging this morning to see what's up.

phil-lgr commented 6 years ago

I just tried putting a:

 after: async () => {
        await browser.pause(2000);
    },

and it seems to fix it, no more chromedriver left behind.

christian-bromann commented 6 years ago

mhm .. but why did it fix it when we wait in the afterHook?

phil-lgr commented 6 years ago

False alert 😅 I still get the idle at the end.. image

@christian-bromann any workaround you could think of or info I could gather?

christian-bromann commented 6 years ago

no idea, something must be up when trying to kill these processes

phil-lgr commented 6 years ago

@FlippieCoetser's solution seems to be the thing to do for now 🙏

janardanb commented 6 years ago

Hi , I am also facing the same issue.. @christian-bromann @phil-lgr is there any solution for it?

christian-bromann commented 6 years ago

@amolebhojane sorry but I can't look into this atm, any PRs or suggestion for fixes are highly appreciated

prantlf commented 6 years ago

I reproduced the problem using just selenium-standalone and webdriverio modules. I logged the issue for selenium-standalone.

I use a short delay after uninitializing the WebdriverIO client as a workaround to get the chromedriver process stopped:

const webdriverio = require('webdriverio')
const client = webdriverio.remote({...})
client.init()
  ...
  .end()
  // the following line helps stopping the chromedriver process after
  // killing the selenium process returned by the start method
  .pause(100)
ghost commented 6 years ago

Ran into this today as well, as a workaround I've simply added this as an npm posttest command "posttest" : "taskkill /FI \"IMAGENAME eq 2.36-x64-chromedriver\" /F" based on @rgustavsson suggestion. Would really like to see a fix from selnium's side though.

phil-lgr commented 6 years ago

I've been running this as a post npm script:

const shell = require('shelljs/shell.js');
shell.exec('taskkill /IM chromedriver.exe /F', {silent: true});
shell.exec('kill -9 $(pgrep chromedriver)', {silent: true});
cuff-links commented 6 years ago

I am having a similar issue. But I am also having the issue where the first test fails with the Connection Reset error. There were no lingering chromedriver sessions open. I run my tests and the first chrome test fails. This started all of a sudden too. I was having no failures and now it just keeps failing.

cuff-links commented 6 years ago

Works fine against saucelabs because each test is run on its own machine. It's only when I run these locally.

phil-lgr commented 6 years ago

@silne30 maybe check https://github.com/webdriverio/wdio-selenium-standalone-service/issues/39

ichipev commented 6 years ago

Hi guys. I was trying to find most proper workaround for that issue for last couple of days. So far adding a script with taskkill /IM "chromedriver*" /F is good one but it will kill all drivers, which means you can't run more than 1 test instance at same time, since this will kill all chromedrivers. It is good way if you don't need to run 2 instance simultaneously. So far best workaround for me was to use afterAll with browser.driver.quit(), unfortunately after some updates afterAll stopped working and I made it as a method that I've put at the end of every test. There is an error but at least works and it doesn't affects the test's results

rycornell commented 6 years ago

I've tried all of the suggestions mentioned above and received inconsistent results. The only way I've gotten it to work consistently is by adding these lines to wdio.conf.js:

afterSession: function(){
    // workaround to make sure the chromedriver shuts down
    browser.end().pause(1000);
},
after: function(){
    // workaround to make sure the chromedriver shuts down
    browser.pause(1000);
}

I don't have a good explanation. Putting browser.end().pause(1000) in the after didn't work. Also tried with only the afterSession code and it didn't work.

Gary-Osteen-Q2 commented 6 years ago
afterSession: async function(){
    // workaround to make sure the chromedriver shuts down
    await browser.end().pause(1000);
},
after: async function(){
    // workaround to make sure the chromedriver shuts down
    await browser.pause(1000);
}

I had to add the async and await bits, then it started working for me to clean them up reliably.

cuff-links commented 6 years ago

Is this the accepted workaround for this issue?

Gary-Osteen-Q2 commented 6 years ago

@silne30 my last comment is the simplest workaround for the issue and I hope it works for you. I'm not sure if I should close this as it isn't fixed.

FlippieCoetser commented 6 years ago

@Gary-Osteen-Q2 I tested and can confirm, your workaround works.

Gary-Osteen-Q2 commented 6 years ago

I've added the workaround to the top to save someone else time until this issue gets fixed.

cuff-links commented 6 years ago

For this workaround, do we have to be running the tests as Async for it to work?

Gary-Osteen-Q2 commented 6 years ago

No. I run it in sync mode. Just the function in the wdio.config.js file needs the aysnc/await tags for it to work and actually wait.

cuff-links commented 6 years ago

Hmmm....those hooks didn't work for me. Still getting the Connection reset by peer or cannot write to server errors. I wonder if it has something to do with my setup.

ghost commented 6 years ago

If you start the wdio runner programmatically using the wdio launcher (const wdio = new Launcher("wdio.conf.js", {port: 9515});) and spawn the selenium and chromedriver processes yourself, and let the tests finsish, the processes disappear on their own. That means under normal circumstances Selenium handles the clean up itself without the need to kill processes.

The problem seems to be rooted in the test runner: node_modules/webdriverio/build/lib/runner.js: process.exit() //case: 50 | line ~280

It probably exits the session too early. I assume the session process is the same that spawned the selenium server via the selenium service module? If so, when it exits it also kills the selenium (java) child process which, at this point, has not shutdown Chromedriver yet.

But that is all a bit iffy though. Because the following workaround should actualy work: Spawn the Java/Selenium process in the selenium-standalone module with the "detached" option true (https://nodejs.org/api/child_process.html#child_process_options_detached). This would decouple the Java process from Node so that Node could exit, leaving the cleanup to Selenium. While this does get rid of the Chromedriver, now a Java process stays open. Does Selenium shut down the driver but not itself then? But it does when running it programmatically!

The only working solution is if you put the process.exit() in runner.js in a (long enough, +100ms) setTimeout. But that is kind of hacky.

ghost commented 5 years ago

Bump. The suggested workaround does not work for new webdriverio v5, cause browser.end() does not exist anymore. Any ideas how to kill running chromedriver after test? @christian-bromann ? Thanks

Edit: leaving await browser.pause(1000); instead of await browser.end().pause(1000); works.

virtuacoplenny commented 5 years ago

Bump. The suggested workaround does not work for new webdriverio v5, cause browser.end() does not exist anymore. Any ideas how to kill running chromedriver after test? @christian-bromann ? Thanks

Edit: leaving await browser.pause(1000); instead of await browser.end().pause(1000); works.

For me, on mac and on v5, I added a call to delete session in the "after" hook and it resolved the cleanup issues.

after: () => {
    browser.deleteSession();
}
ampc commented 5 years ago

On linux I had to edit this hooks:

 /**
   * Gets executed after all tests are done. You still have access to all global variables from
   * the test.
   * @param {Number} result 0 - test pass, 1 - test fail
   * @param {Array.<Object>} capabilities list of capabilities details
   * @param {Array.<String>} specs List of spec file paths that ran
   */
  after: function(result, capabilities, specs) {
    browser.pause(1000);
  },
  /**
   * Gets executed right after terminating the webdriver session.
   * @param {Object} config wdio configuration object
   * @param {Array.<Object>} capabilities list of capabilities details
   * @param {Array.<String>} specs List of spec file paths that ran
   */
  afterSession: function(config, capabilities, specs) {
    browser.pause(1000);
  },
bonrg commented 5 years ago

clearing the object helped in my case Python example: browser = webdriver.Chrome( executable_path=self.WEBDRIVER_PATH, options=options ) del(browser)

gamerchandu commented 4 years ago

workaround :

  1. Go to chrome://settings
  2. Advanced settings
  3. Disable this option 'Continue running background apps when Google Chrome is closed'