2

I am using "selenium-java.jar" file to open chrome headless drivers. Now we are using threads to open headless chrome. Now what happens if there is any error then sometime threads quits without closing browser.

So i want to implement a solution that if any headless chrome is ideal for last 20 minutes then close/quit it.

I searched on google and i found may solution which is around selenium server standalone like this https://github.com/seleniumhq/selenium/issues/1106

My problem is i cannot switch to standalone server now so i have to figure out solution with current library.

So is there any way to close all headless chrome browsers which are idle for last 20 minutes?

Please guide.

Ankur Raiyani
  • 1,509
  • 5
  • 21
  • 49
Dilip Dalwadi
  • 167
  • 2
  • 10

3 Answers3

3

I use selenium-java.jar with TestNg and whilst I don't run headless browsers I do clean up after a test run in the TestNg aftermethod, which is not quite the same as your 20 min wait, but might be of help.

When running tests on a windows OS I check for to see if the process is running by name and terminate it:

public final class OsUtils
{
    private static final String TASKLIST = "tasklist";
    private static final String KILL = "taskkill /F /IM ";
    public static final String  IE_EXE = "iexplore.exe";
    public static final String  CHROME_EXE = "chrome.exe";
    public static final String  EDGE_EXE = "MicrosoftEdge.exe";
    public static final String  FIREFOX_EXE = "firefox.exe";


public static boolean isProcessRunning(String processName)
{
    Process process;
    try
    {
        process = Runtime.getRuntime().exec(TASKLIST);
    }
    catch (IOException ex)
    {
        Logger.error("Error on get runtime" + ex.getMessage());
        return false;
    }

    String line;
    try ( BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); )
    {
        while ((line = reader.readLine()) != null) {
            if (line.contains(processName)) {
                Logger.log("Process found");
                return true;
            }
        }
    }
    catch (IOException ex)
    {
        Logger.error("Error on check for process " + processName + ": " + ex.getMessage());
    }
    return false;
}

public static void killProcessIfRunning(String processName)
{
    Logger.log("Trying to kill process: " + processName);
    try
    {
        if (isProcessRunning(processName))
        {
            Runtime.getRuntime().exec(KILL + processName);
        }
    }
    catch (IOException ex)
    {
        Logger.error("Error on kill process " + processName+ ": " +  ex.getMessage());
    }
}
...
}

When running Safari on macmini I have a similar kill command (which works for both Safari proper and also the technology preview):

public static void killSafariProcess()
{
    Logger.log("Trying to kill Safari processes if running.");

    try
    {
        Process p = Runtime.getRuntime().exec(new String[]{"bash","-c","ps ux | grep -i app/Contents/MacOs/Safari | grep -v grep | awk '{print $2}' | xargs kill -9"});
    }
    catch (IOException ex)
    {
        Logger.error("Error on kill Safari processes: " +  ex.getMessage());
    }
}

The custom Logger class just uses System.out.println(message)

elworthy
  • 454
  • 4
  • 12
  • This approach is going to prevent running scripts in parallel. – JeffC Jan 31 '19 at 17:42
  • Yep, your suggestions below would help, or 1) Pulling a process ID found list at test end, storing those with the time you found them, persist the data between runs and thus know a PID is long running. 2) Or even get the list before the browser is launched, update the list once browser launched and thus know the new PID is the one to kill. Could still pickup a parallel run ID, but we're dealing with an edge case here, both PIDs still up after 20 mins kill them both. Option for OP to investigate along with your suggestions. – elworthy Jan 31 '19 at 19:09
0

You can probably do some analysis on the start time of the different processes that match your driver criteria. I don't think it's going to tell you how long it's been idle, but you can probably assume that if it's been running for 20 mins (assuming your test should successfully complete within minutes) that it's probably orphaned.

I found this answer that shows how you can use Java to get a list of processes and see their start time. From there you should be able to find all of the drivers that are old and kill them.

An alternative might be to use Powershell to get the processes, start time, and deal with it in that way. It just depends on what you are looking for. Here's an answer to get you started down this path.

JeffC
  • 22,180
  • 5
  • 32
  • 55
0

You could subclass ChromeDriver and implement your own proxy class with a timer to quit after 20 minutes idle time:

public class TimedChromeDriver extends ChromeDriver {

  Timer timeOut;

  private void initTimer() {
    timeOut = new Timer();
  }

  private void startTimer() {
    timeOut.cancel();
    timeOut.schedule(
        new TimerTask() {
          @Override
          public void run() {
            quit();
          }
        },
        20 * 60 * 1000);
  }

  public TimedChromeDriver() {
    initTimer();
  }

  @Override
  public void get(String url) {
    super.get(url);
    startTimer();
  }

  // override every method of WebDriver and ChromeDriver in the same way
}

This will only work if your Java VM is not terminated before the timer is triggered. The garbage collector could also interfere. Overriding the finalize method is deprecated.

I would invest some analysis effort into your threads quitting ungracefully. This would solve your problems at the source.

Jens Dibbern
  • 1,434
  • 2
  • 13
  • 20