How can i close all idle web browsers opened by selenium? - java

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.

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)

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.

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.

Related

Jar file working when running standalone but doesn't work under Windows service

I have a java project, which complied into an executable jar file v-agent-exe.jar. This jar is a log server, log rows is sent to it for processing.
I can execute it by using this command:
`java -jar v-agent-exe.jar -a watch -f config.ini`.
After executed, this jar file will create a ServerSocket at port 1235 and listen for incoming data from clients. After data received, the program will process the data and send the result back to the client. When I execute the jar from CMD windows, the processing is working perfect.
Now I am trying to wrap the Jar file as a Windows service (I am using Windows 10). I created a "Windows service project"
in Visual studio like below:
- Caller class have call() method to execute the jar file using process.
- AgentService is the service, which execute Caller->call() in another thread.
- Program is the main entry to load AgentService.
Caller.cs
public class Caller
{
static Process proc;
public Process GetProcess(){
return proc;
}
public void call() {
try
{
String dir = AppDomain.CurrentDomain.BaseDirectory;
proc = new Process
{
StartInfo = new ProcessStartInfo
{
WorkingDirectory = dir,
FileName = "java.exe",
Arguments = #"-jar v-agent-exe.jar -a watch -f config.ini",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
CreateNoWindow = true
}
};
proc.Start();
while (!proc.StandardError.EndOfStream)
{
string line = proc.StandardError.ReadLine();
}
}
catch (Exception ex) {
VAgentService.writeLog("Error when call process: " + ex.Message);
}
}
}
AgentService
public partial class AgentService : ServiceBase
{
private string jarPath;
private string iniPath;
static Process proc;
Caller caller;
public AgentService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
writeLog("On start");
try
{
caller = new Caller();
writeLog("Prepare to launch thread");
Thread t = new Thread(new ThreadStart(caller.call));
t.Start();
}
catch (Exception ex)
{
EventLog.WriteEntry("Demo error: " + ex.Message);
}
}
protected override void OnStop()
{
proc = caller.GetProcess();
if (proc != null && !proc.HasExited)
{
proc.Kill();
}
else
{
...
}
}
}
Program.cs
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(String[] args)
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new AgentService()
};
ServiceBase.Run(ServicesToRun);
}
}
After build the the service project, I have AgentService.exe.
I install it to my system using:
sc create VAgentLogging binpath= %CD%\AgentService.exe depend= lmhosts start= auto
After start the service in service.msc, I can telnet to port "1235" which the java process is listening (I am sure about
only the jar running in this port). According to the
log of java program, it still can received some part of data but seem like it cannot send back to client or something,
which cause the followed process cannot be done.
I think my problem is: the jar file can executed as standalone but somehow it sucks when wrapped under my service project.
I haven't posted the jar's code yet because I think the error is related to the Windows service project. If you need the java code, please tell me and I will update it here.
Any help would be appreciated.

Gracefully kill process open by Java in Android

I'm trying to execute ping command in my Android application and be able to cancel it / send break signal. Basically I want to get ping statistics after like when you send ctrl+c to ping in any normal linux.
I have read Send Ctrl-C to process open by Java but it aims for Windows platform and tbh seems a little bit like an overkill. My code for executing the command (I'm using rxjava):
public rx.Observable<String> getPingOutput(String address)
{
return rx.Observable.create(new rx.Observable.OnSubscribe<String>()
{
#Override
public void call(Subscriber<? super String> subscriber)
{
try
{
process = Runtime.getRuntime().exec("ping -c 4 " + address);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s = stdInput.readLine()) != null)
{
subscriber.onNext(s);
}
subscriber.onCompleted();
process.destroy();
stdInput.close();
}
catch (IOException e)
{
subscriber.onError(e);
if(process != null)
{
process.destroy();
}
}
}
});
}
And starting / canceling:
RxView.clicks(pingButton)
.subscribe(new Action1<Void>()
{
#Override
public void call(Void aVoid)
{
if (isPingInProgress())
{
process.destroy();
subscription.unsubscribe();
isPing = false;
pingButton.setText("Ping");
}
else
{
if(adapter!= null)
{
adapter.clear();
adapter.notifyDataSetChanged();
}
String address = addressInput.getText().toString();
subscription = getPingOutput(address)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(myObserver);
isPing = true;
pingButton.setText("Stop");
}
}
});
So far I tried just killing the process but that immediately stops all output. And ideas how can I "gracefully" stop the ping command started by Java in Android?
EDIT
So I managed to get PID of my ping process, verified its correct via adb console. I tried to kill it using:
Runtime.getRuntime().exec("kill -INT " + getPid(process));, there is no ErrorStream output but nothing happens. Same for Process.sendSignal(getPid(process),Process.SIGNAL_QUIT);. Anyone?
Problem solved, turns out it didn't react to signals because I ran ping on separate thread.

how to close an application in java by releasing memory

I am using a java application which opens a scratch file during run time. The scratch file communicates with the arduino board and gives the output. once the communication starts i am unable to use my User interface in java which has a close button instead i tried closing my entire application using end task in task manager. Can you please tell me as how to release the memory associated with the files. I used process. destroy and system.exit(0) but did not work.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
if("Disconnect".equals(jButton1.getText()))
{
System.exit(0);
}
jButton1.setText("Disconnect");
if(jComboBox2.getSelectedItem()==null)
{
System.out.println("Select one port");
}
else
{ Runtime r = Runtime.getRuntime();
try {
this.hide();
//p = r.exec("C:\\Program Files\\Scratch 2\\Scratch 2.exe C:\\Users\\Admin\\Desktop\\fwdbckpwm12.sb2");
p = Runtime.getRuntime().exec("C:\\Program Files\\Scratch 2\\Scratch 2.exe C:\\Users\\Admin\\Desktop\\scratch files new.sb2");
//p.destroy();
//r.exec("C:\\Windows\\notepad.exe C:\\Windows\\ss.txt");
A4S a4sObj = new A4S(new String[]{jComboBox2.getSelectedItem().toString()}); //defaultline
// A4S a4sObj = new A4S(new String[]{"COM16"}); //addedline
r.gc();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
} catch (IOException ex) {
Logger.getLogger(serialportselection.class.getName()).log(Level.SEVERE, null, ex);
}
finally{
p.destroy();
System.gc();
}
}
}

MIDI OUT transmitter not available

I've been banging my head on this all day, read everything I can find, followed the JDK source around, no luck in finding out the gory details about HOW or WHERE java looks to obtain data on a midi device and determines what's what.
I'm trying to capture midi messages through my NI Audio 8 DJ MIDI IN port, but, java isn't "seeing" the MIDI IN port, only the out, which I have successfully used to send midi with. I also get the same results with an M-Audio USB UNO midi device: MidiSystem.getMidiDeviceInfo() only "sees" the output port.
I have verified the operation of the MIDI IN port with:
amidi -p hw:2,0 -d
and sending it some signals. Works fine.
getMaxTransmitters() returns zero.
MidiSystem.getMidiDeviceInfo() shows only one entry for both devices: Audio8DJ [hw:2,0] or Interface [hw:2,0]
The code below works fine for a Receiver and I think is only the bits I need to verify that getTransmitter() grabs the port, since it just works for the other and everything works fine, up I get a MidiUnavailableException / Transmitter not available exception.
I've even taken the getMaxReceivers() trap out because I was just trying to see if the device only offered up the one entry and sorted it out, but no.
public static Transmitter getMidiIn () {
if (midiIn == null){
devices = MidiSystem.getMidiDeviceInfo();
for(MidiDevice.Info info: devices){
System.out.println("device class " + info.getClass());
MidiDevice device;
try{
device = MidiSystem.getMidiDevice(info);
if (info.toString().equals("Audio8DJ [hw:2,0]")){
if (device.getMaxTransmitters() != 0){
try{
device.open();
System.out.println("max transmitters:" + device.getMaxTransmitters());
midiIn = device.getTransmitter();
System.out.println("Found a transmitter: "+ midiIn);
break;
} catch (Exception e){
e.printStackTrace();
}
}
}
} catch (MidiUnavailableException e1){
e1.printStackTrace();
}
}
}
return midiIn;
}
So the thing that's getting me here is this: alsa lists only one entry in amidi -l and when I specify that as a port to dump, it works fine. Java gets that same text entry and can't sort out the MIDI IN, assigning it the com.sun.media.sound.MidiOutDeviceProvider class so it leaves me wondering just how does, or where does Java figure out what a device has to offer and why isn't it seeing the input port that alsa is seeing.
I'm coding with eclipse Version: 3.8.1 IDE with JDK1.6, on a linux mint OS, .
I'll be happy to provide anything asked for. Thanks for reading!
The solution to java seeing the transmitter was in the version of JDK being used, though unfortunately at this time, I do not have an answer as to why for the failure, just that one version worked and suits my needs for the time being. If I find that answer, I will edit this answer.
Of the three versions I was switching between for testing, jdk1.8.0_60, jdk1.7.0_80, jdk1.6.0_45, 1.7 did not experience the error and successfully obtained a transmitter from my device. I found this out, and that privileges were not the cause of my specific issue, by compiling and running some code I found suitable for command line execution that attempts to obtain the transmitter, prints out midi data sent to it, and modified it a little ...
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
public class MidiInputTest {
public MidiDevice input;
public MidiDevice output;
public static void main(String[] args) {
new MidiInputTest().start();
}
public void start() {
init(); // initialize your midi input device
// system dependent
try {
output.open(); // From midi device
MyReceiver myrcvr = new MyReceiver();
MidiSystem.getTransmitter().setReceiver(myrcvr);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
private class MyReceiver implements Receiver {
Receiver rcvr;
public MyReceiver() {
try {
this.rcvr = MidiSystem.getReceiver();
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
#Override
public void send(MidiMessage message, long timeStamp) {
byte[] b = message.getMessage();
if (b[0] != (byte)254) {
System.out.println((b[0] & 0xff) + " " + (b[1] & 0xff));
}
//rcvr.send(message, timeStamp); // will send out what ever you receive
}
#Override
public void close() {
rcvr.close();
}
}
public void init() {
MidiDevice.Info[] devices;
devices = MidiSystem.getMidiDeviceInfo();
try{
for (MidiDevice.Info info: devices) {
MidiDevice device;
device = MidiSystem.getMidiDevice(info);
System.out.println("MidiDevice.Info="+info + "\n" + "maxTransmitters="+device.getMaxTransmitters());
// I put the specific device I want to connect to behind an if gate here to avoid connecting to something I do not
if (info.toString().equals("Interface [hw:2,0,0]") && device.getMaxTransmitters() != 0) {
System.out.println(" Name: " + info.toString() +
", Decription: " +
info.getDescription() +
", Vendor: " +
info.getVendor());
output = MidiSystem.getMidiDevice(info);
if (! output.isOpen()) {
output.open();
}
}
}
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
}
To run this from the command line choose a version of JDK you have installed, compile and run it with those specific versions substituting jdk1.7.0_80 for the distro you wish to test.
/opt/java-jdk/jdk1.7.0_80/bin/javac MidiInputTest.java
/opt/java-jdk/jdk1.7.0_80/bin/java -cp . MidiInputTest
Though I haven't been able to verify it, Java Sound is apparently responsible for figuring out what is available for java's use from your MIDI architecture.
Thank you Mike Harris for sending me down the right path of testing on the command line, and jim829 over at java-forums.org for the example code for the command line.
I had this problem which was caused by multiple instances of device info with the same name reterned by MidiSystem.getMidiDeviceInfo(). Basically when you call MidiSystem.getMidiDevice(Info) if you're unlucky it'll return the one without the transmitter. I'm not sure why it does this but only one instance has transmitters, (I think one might be for in and one out but, not sure). By first getting just the devices that have transmitters and then selecting from these, with the desired info, it worked for me. Hope that helps
public ArrayList<MidiDevice> getTransmitterDevices() {
MidiDevice.Info[] deviceInfo = MidiSystem.getMidiDeviceInfo();
ArrayList<MidiDevice> transmitterDevices = new ArrayList<>();
for(int i=0;i<deviceInfo.length;i++) {
try {
MidiDevice device = MidiSystem.getMidiDevice(deviceInfo[i]);
if(device.getMaxTransmitters()!=0) {
transmitterDevices.add(device);
}
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return transmitterDevices;
}
//Somewhere else
//choose appropriate info somehow
MidiDevices<ArrayList> transmitterDevices = getTransmitterDevices();
for(MidiDevice tmp : transmitterDevices) {
if(tmp.getDeviceInfo().equals(info)) {
try {
midiController = tmp;
Transmitter transmitter = midiController.getTransmitter();
// something that implements receiver
midiReceiver = new MidiReceiver();
transmitter.setReceiver(midiReceiver);
midiController.open();
System.out.println("controller set ok");
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Spark Launcher waiting for job completion infinitely

I am trying to submit a JAR with Spark job into the YARN cluster from Java code. I am using SparkLauncher to submit SparkPi example:
Process spark = new SparkLauncher()
.setAppResource("C:\\spark-1.4.1-bin-hadoop2.6\\lib\\spark-examples-1.4.1-hadoop2.6.0.jar")
.setMainClass("org.apache.spark.examples.SparkPi")
.setMaster("yarn-cluster")
.launch();
System.out.println("Waiting for finish...");
int exitCode = spark.waitFor();
System.out.println("Finished! Exit code:" + exitCode);
There are two problems:
While submitting in "yarn-cluster" mode, the application is sucessfully submitted to YARN and executes successfully (it is visible in the YARN UI, reported as SUCCESS and pi is printed in the output). However, the submitting application is never notified that processing is finished - it hangs infinitely after printing "Waiting to finish..." The log of the container can be found here
While submitting in "yarn-client" mode, the application does not appear in YARN UI and the submitting application hangs at "Waiting to finish..." When hanging code is killed, the application shows up in YARN UI and it is reported as SUCCESS, but the output is empty (pi is not printed out). The log of the container can be found here
I tried to execute the submitting application both with Oracle Java 7 and 8.
I got help in the Spark mailing list. The key is to read / clear getInputStream and getErrorStream() on the Process. The child process might fill up the buffer and cause a deadlock - see Oracle docs regarding Process. The streams should be read in separate threads:
Process spark = new SparkLauncher()
.setSparkHome("C:\\spark-1.4.1-bin-hadoop2.6")
.setAppResource("C:\\spark-1.4.1-bin-hadoop2.6\\lib\\spark-examples-1.4.1-hadoop2.6.0.jar")
.setMainClass("org.apache.spark.examples.SparkPi").setMaster("yarn-cluster").launch();
InputStreamReaderRunnable inputStreamReaderRunnable = new InputStreamReaderRunnable(spark.getInputStream(), "input");
Thread inputThread = new Thread(inputStreamReaderRunnable, "LogStreamReader input");
inputThread.start();
InputStreamReaderRunnable errorStreamReaderRunnable = new InputStreamReaderRunnable(spark.getErrorStream(), "error");
Thread errorThread = new Thread(errorStreamReaderRunnable, "LogStreamReader error");
errorThread.start();
System.out.println("Waiting for finish...");
int exitCode = spark.waitFor();
System.out.println("Finished! Exit code:" + exitCode);
where InputStreamReaderRunnable class is:
public class InputStreamReaderRunnable implements Runnable {
private BufferedReader reader;
private String name;
public InputStreamReaderRunnable(InputStream is, String name) {
this.reader = new BufferedReader(new InputStreamReader(is));
this.name = name;
}
public void run() {
System.out.println("InputStream " + name + ":");
try {
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Since this is an old post, i would like to add an update that might help whom ever read this post after. In spark 1.6.0 there are some added functions in SparkLauncher class. Which is:
def startApplication(listeners: <repeated...>[Listener]): SparkAppHandle
http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.launcher.SparkLauncher
You can run the application with out the need for additional threads for the stdout and stderr handling plush there is a nice status reporting of the application running. Use this code:
val env = Map(
"HADOOP_CONF_DIR" -> hadoopConfDir,
"YARN_CONF_DIR" -> yarnConfDir
)
val handler = new SparkLauncher(env.asJava)
.setSparkHome(sparkHome)
.setAppResource("Jar/location/.jar")
.setMainClass("path.to.the.main.class")
.setMaster("yarn-client")
.setConf("spark.app.id", "AppID if you have one")
.setConf("spark.driver.memory", "8g")
.setConf("spark.akka.frameSize", "200")
.setConf("spark.executor.memory", "2g")
.setConf("spark.executor.instances", "32")
.setConf("spark.executor.cores", "32")
.setConf("spark.default.parallelism", "100")
.setConf("spark.driver.allowMultipleContexts","true")
.setVerbose(true)
.startApplication()
println(handle.getAppId)
println(handle.getState)
You can keep enquering the state if the spark application until it give success.
For information about how the Spark Launcher server works in 1.6.0. see this link:
https://github.com/apache/spark/blob/v1.6.0/launcher/src/main/java/org/apache/spark/launcher/LauncherServer.java
I implemented using CountDownLatch, and it works as expected.
This is for SparkLauncher version 2.0.1 and it works in Yarn-cluster mode too.
...
final CountDownLatch countDownLatch = new CountDownLatch(1);
SparkAppListener sparkAppListener = new SparkAppListener(countDownLatch);
SparkAppHandle appHandle = sparkLauncher.startApplication(sparkAppListener);
Thread sparkAppListenerThread = new Thread(sparkAppListener);
sparkAppListenerThread.start();
long timeout = 120;
countDownLatch.await(timeout, TimeUnit.SECONDS);
...
private static class SparkAppListener implements SparkAppHandle.Listener, Runnable {
private static final Log log = LogFactory.getLog(SparkAppListener.class);
private final CountDownLatch countDownLatch;
public SparkAppListener(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
#Override
public void stateChanged(SparkAppHandle handle) {
String sparkAppId = handle.getAppId();
State appState = handle.getState();
if (sparkAppId != null) {
log.info("Spark job with app id: " + sparkAppId + ",\t State changed to: " + appState + " - "
+ SPARK_STATE_MSG.get(appState));
} else {
log.info("Spark job's state changed to: " + appState + " - " + SPARK_STATE_MSG.get(appState));
}
if (appState != null && appState.isFinal()) {
countDownLatch.countDown();
}
}
#Override
public void infoChanged(SparkAppHandle handle) {}
#Override
public void run() {}
}

Categories

Resources