Reputation: 421
I have a RMI client testing if a RMI server is running and reachable.
At the moment I perform every few seconds this test:
try {
rMIinstance.ping();
} catch (RemoteException e) {
getInstanceRegister().removeInstance(rMIinstance);
}
(ping()
is a simple dummy RMI call.)
If the instance is offline the I get approx 1 minute later a
java.net.ConnectException: Connection timed out
exception, showing me that the server is offline.
However the code hangs one minute, which is far to long for us. (I don't want to change the timeout setting.) Is there a method to perform this test faster?
Upvotes: 3
Views: 6525
Reputation: 310850
Set the system property sun.rmi.transport.proxy.connectTimeout
to the desired connect timeout in milliseconds. I would also set sun.rmi.transport.tcp.responseTimeout
.
The answers suggesting interrupting the thread rely on platform-specific behaviour of java.net
, whose behaviour when interrupted is undefined.
Upvotes: 0
Reputation: 132350
The proposed solutions that interrupt the thread making the RMI call might not work, depending on whether that thread is at a point where it can be interrupted. Ordinary in-progress RMI calls aren't interruptible.
Try setting the system property java.rmi.server.disableHttp
to true
. The long connection timeout may be occurring because RMI is failing over to its HTTP proxying mechanism. This mechanism is described -- albeit very briefly -- in the class documentation for RMISocketFactory. (The HTTP proxying mechanism has been deprecated in JDK 8).
Upvotes: 0
Reputation: 421
Inspired by the answer of @NeplatnyUdaj I found this solution:
try {
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new Task(rMIinstance));
System.out.println("Result: "+ future.get(3, TimeUnit.SECONDS));
} catch (RemoteException | TimeoutException e) {
getInstanceRegister().removeInstance(rMIinstance);
}
And this task:
class Task implements Callable<String> {
DatabaseAbstract rMIinstance;
public Task(DatabaseAbstract rMIinstance)
{
this.rMIinstance = rMIinstance;
}
@Override
public String call() throws Exception {
rMIinstance.ping();
return "OK";
}
}
Upvotes: 1
Reputation: 6242
You could interrupt the thread from a timer. It's a bit hacky and will throw InterruptedException instead of RemoteException, but it should work.
try {
Timer timer = new Timer(true);
TimerTask interruptTimerTask = new InterruptTimerTask(Thread.currentThread());
timer.schedule(interruptTimerTask, howLongDoYouWantToWait);
rMIinstance.ping();
timer.cancel();
} catch (RemoteException | InterruptedException e) {
getInstanceRegister().removeInstance(rMIinstance);
}
And the TimerTask implementation:
private static class InterruptTimerTask extends TimerTask {
private Thread thread;
public InterruptTimerTask(Thread thread) {
this.thread=thread;
}
@Override
public void run() {
thread.interrupt();
}
}
Upvotes: 2