Search code examples
javaseleniumselenium-gridgeckodriver

Monitor and gracefully kill or reuse zombie GeckoDriver instances


Selenium is designed to kill Geckodriver process when disposing of the webdriver instance like this: driver.quit(). In my testing framework, I have configured to call driver.quit() after each test.

In some cases however, the test terminates abnormally due to various reason and then the finalizing steps (like quitting the driver) are not being executed. As a result I end up with multiple geckodriver processes that I can only kill manually.

Is there any good practice how to work around this problem? Perhaps monitoring the processes somehow and killing the ones that do not transfer any data?

Or maybe creating few instances and then reusing them?

I am running my tests on Grid so manipulating the process through command line won't work as it will only affect the grid hub.

EDIT:

There is an option of using taskkill to terminate all the geckodriver processes on a machine but this is not a good solution since:

  1. I am running my tests through Selenium Grid so this will only affect the grid hub and not the nodes.
  2. There are multiple tests that run simultaneously and if I use taskkill I will kill the ones that are still in use as well.
  3. I don't think that killing the processes using taskkill is a generally a good practice I would like to find a more elegant solution. E.g. (1)geckodriver processes are monitored on the node and only terminated locally when they are not in use or (2)somehow reused.

Solution

  • I am going to summarise what I posted as a response to the same question on the Selenium-Users google forum

    When Driver.quit() is invoked in the Grid mode, here's what happens :

    • The client (The JVM that runs your test method) sends a delete session request to the Hub.
    • The hub forwards the delete session request to the corresponding node.
    • At the node, the selenium standalone jar translates the delete session request to a call to DriverCommandExecutor.execute() which then gets forwarded to DriverService.stop()

    DriverService.stop() internally triggers a call to http://localhost:port/shutdown (true for ChromeDriver, but for Firefox, the implementation checks for the availability of the port on which geckodriver was started).

    In some cases however, the test terminates abnormally due to various reason and then the finalizing steps (like quitting the driver) are not being executed. As a result I end up with multiple geckodriver processes that I can only kill manually.

    In order to get this sorted out, you can configure timeouts at the node level.

    Quoting the documentation

    -timeout, -sessionTimeout in seconds : Specifies the timeout before the server automatically kills a session that hasn't had any activity in the last X seconds. The test slot will then be released for another test to use. This is typically used to take care of client crashes. For grid hub/node roles, cleanUpCycle must also be set. Default: 1800

    -browserTimeout in seconds : number of seconds a browser session is allowed to hang while a WebDriver command is running (example: driver.get(url)). If the timeout is reached while a WebDriver command is still processing, the session will quit. Minimum value is 60. An unspecified, zero, or negative value means
    wait indefinitely. Default: 0

    See here and here

    When you configure the timeouts via one of the above cited mechanisms, and when the node detects inactivity on a browser window due to

    1. due to either the client crashing (your test case is the client) or
    2. due to the browser going into a hung state (perhaps due to a rogue javascript) or
    3. due to your test case, opening a browser window and not doing anything on it,

    The above detailed code flow will get triggered and both the orphan browser and also the associated server binary will be cleaned up. If its not happening then its a bug and you would need to raise an issue and provide a simple standalone test, which can be executed to reproduce the problem.