2013-12-18 4 views
3

У меня есть клиент RMI тестирование, если сервер RMI работает и доступен.Есть ли эффективный способ проверить, работает ли RMI-сервер?

На данный момент я выполняю каждые несколько секунд этого тест: (. ping() является простым манекеном RMI вызова)

try { 
    rMIinstance.ping(); 
} catch (RemoteException e) { 
    getInstanceRegister().removeInstance(rMIinstance); 
} 

Если экземпляр офлайн я получаю около 1 минуты в

java.net.ConnectException: Connection timed out

исключение, показывающее, что сервер отключен.

Однако код стоит на одной минуте, что далеко не для нас. (Я не хочу изменять настройку таймаута.) Есть ли способ быстрее выполнить этот тест?

ответ

2

Вы можете прервать поток из таймера. Это немного взломанный и будет вызывать InterruptedException вместо RemoteException, но он должен работать.

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); 
} 

И реализация TimerTask:

private static class InterruptTimerTask extends TimerTask { 
    private Thread thread; 

    public InterruptTimerTask(Thread thread) { 
     this.thread=thread; 
    } 

    @Override 
    public void run() { 
     thread.interrupt(); 
    } 

} 
1

Вдохновленный ответом @NeplatnyUdaj я нашел это решение:

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); 
} 

И эту задачу:

class Task implements Callable<String> { 
     DatabaseAbstract rMIinstance; 
     public Task(DatabaseAbstract rMIinstance) 
     { 
      this.rMIinstance = rMIinstance; 
     } 
     @Override 
     public String call() throws Exception { 
      rMIinstance.ping(); 
      return "OK"; 
     } 
    } 
+1

Небольшой совет: обычно вы должны использовать «ExecutorService», поскольку его целью является «кеширование» потоков. –

0

предлагаемые решения, которые прерывают поток, вызывающий вызов RMI, может не работать, в зависимости от того, находится ли этот поток в точке, где он может быть прерван. Обычные входящие вызовы RMI не прерываются.

Попробуйте установить системное свойство java.rmi.server.disableHttp на true. Длительный таймаут соединения может произойти, потому что RMI отказывается от своего механизма HTTP-проксирования. Этот механизм описан - хотя и очень кратко - в документации по классу для RMISocketFactory. (Механизм HTTP-проксирования устарел в JDK 8).

+0

Я протестировал 'java.rmi.server.disableHttp' =' true'. Это не уменьшило длительный таймаут соединения. – user2661619

+0

О, хорошо, стоило попробовать. Похоже, что у вас проблемы с подключением на низком уровне, когда это происходит. Попробуйте сначала выполнить ping, чтобы узнать, доступен ли хост и ответ, прежде чем пытаться RMI. –

0

Установите системное свойство sun.rmi.transport.proxy.connectTimeout на требуемый тайм-аут соединения в миллисекундах. Я бы также установил sun.rmi.transport.tcp.responseTimeout.

Ответы, предлагающие прерывание потока, зависят от поведения конкретной платформы java.net, поведение которого при прерывании не определено.

+0

Спасибо за подсказку о прерывании. Проблема с таймаутом заключается в том, что другие экземпляры RMI на этой виртуальной машине должны иметь определенный допуск по таймауту. – user2661619

+0

Поэтому используйте более длительный тайм-аут, соответствующий другим удаленным методам, и полностью избавитесь от этого. Другие методы будут генерировать исключения, если истечет время ожидания. – EJP

Смежные вопросы