Is there an effective way to test if a RMI server is up?

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

Answers (4)

user207421
user207421

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

Stuart Marks
Stuart Marks

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

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

NeplatnyUdaj
NeplatnyUdaj

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

Related Questions