6

Selenium sometimes fails to close after calling driver.quit() when it gets stuck at "connection to server was reset" or when it simply "stops responding". When this occurs, it is impossible kill the process (browser) using WebDriver directly, the only way I can think of is by retrieving the PID of browser and destroying process via:

String cmd = "taskkill /F /PID " + pidOfBrowser;
Runtime.getRuntime().exec(cmd);

I'm aware of this response which suggests retrieving a list of processes currently running and filtering it down to Firefox browser. However, as someone pointed out in one of the comments this does not work if a user has many concurrent sessions running and only wishes to kill a select few.

Another solution suggested in the comment section of that thread is to get a list of PIDs from the browser before starting, and only close those that were not running before the test started (so any browser launched manually before tests began won't close)

However, this does not apply to my situation because I am launching many browsers at a time from my program (not manually) and only wish to close some of the browsers launched (the ones that are hanging and not responding to WebDriver anymore).

How can I get PID of a specific Firefox WebDriver session (ideally when it is created) so I can kill the process later if it hangs or gets 'stuck'?

Thanks!

S.O.S
  • 848
  • 10
  • 30
  • 1
    how about this `from selenium import webdriver driver = webdriver.Firefox() print(driver.service.process.pid)` from [here](https://stackoverflow.com/questions/10752512/get-pid-of-browser-launched-by-selenium) . when you close , make sure you bring the window in focus and use `driver.close()` as driver.quit()` will close all windows – user1207289 Sep 04 '19 at 19:55
  • We don't clean up mid run... we wait until the run is complete and then kill all processes (or kill all before a run starts). Why do you need to clean up mid run? – JeffC Sep 04 '19 at 20:29
  • @JeffC I'm launching browser after browser - as long as system detects there's sufficient memory, next browser is launched automatically so there is no delay between launches. If I have to wait until all browsers finish doing their work before launching the next set of browsers it will slow down system.. as each browser can take different amount of time to complete work. This is why I need to kill browser as soon as I detect it is 'stuck' so I could launch a replacement immediately.. – S.O.S Sep 04 '19 at 21:33
  • @user1207289 that thread is in Python. I don't see how to do this with Java. If it's possible to get PID of Firefox session/brwoser in Java please post as solution and I will accept. Thanks! – S.O.S Sep 04 '19 at 21:35
  • What about this? https://stackoverflow.com/questions/40467793/how-can-i-get-chromedriver-process-pid-using-java – Hasitha Jayawardana Sep 05 '19 at 05:29

2 Answers2

1

You can kill the Browser instance initiated using Selenium retriving the PID from the capabilities object and then invoking getRuntime() with taskkill /PID as follows:

  • Code Block:

    import java.io.IOException;
    import org.openqa.selenium.Capabilities;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.firefox.FirefoxDriver;
    import org.openqa.selenium.remote.RemoteWebDriver;
    
    public class Kill_Firefox_PID {
    
        public static void main(String[] args) throws IOException {
    
            System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
            WebDriver driver = new FirefoxDriver();
            Capabilities cap = ((RemoteWebDriver) driver).getCapabilities();
            System.out.println("moz:processID value is : "+cap.getCapability("moz:processID"));
            Runtime.getRuntime().exec("taskkill /PID "+cap.getCapability("moz:processID"));
        }
    }
    
  • Console Output:

    moz:processID value is : 8492
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • Upvoted. Thanks. Will accept as final solution later today. Just one question: Is it possible to achieve this without casting to RemoteWebDriver? As I currently don't rely on RemoteWebDriver but I guess casting to RemoteWebDriver can't hurt.. – S.O.S Sep 05 '19 at 17:30
  • @S.O.S Yes, it's possible through os level client calls but comparatively using [`getCapabilities()`](https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/remote/RemoteWebDriver.html#getCapabilities--) things are much simpler. – undetected Selenium Sep 05 '19 at 19:22
  • @DebanjanB Is it possible to get the geckodriver process that is associated with driver instance using capabilities ? – Alan Cook Nov 04 '19 at 18:05
  • @AlanCook Yes it's possible but that's a separate question and you may have to raise a new ticket. – undetected Selenium Nov 06 '19 at 07:38
1

In Java 9+ version you can do like this. It is taken from here

public static void main(String[] args) {
    ProcessHandle.allProcesses()
            .forEach(process -> System.out.println(processDetails(process)));
}

private static String processDetails(ProcessHandle process) {
    return String.format("%8d %8s %10s %26s %-40s",
            process.pid(),
            text(process.parent().map(ProcessHandle::pid)),
            text(process.info().user()),
            text(process.info().startInstant()),
            text(process.info().commandLine()));
}

private static String text(Optional<?> optional) {
    return optional.map(Object::toString).orElse("-");
}

and then get info of the process like above. There is a totalCpuDuration​() method in ProcessHandle.Info class. use this to see which process is taking long and then act accordingly. There are other methods in that class that can be beneficial in your scenario. Hope this helps.

user1207289
  • 3,060
  • 6
  • 30
  • 66