2016-05-15 5 views
0

Я работаю над библиотекой, где я делаю вызов Http для моей службы, и если моя служебная машина не отвечает (есть тайм-аут сокета или время ожидания соединения), я добавьте их в мой локальный blockList, и если машина заблокирована 5 раз, я не звоню им.Заблокируйте частичную машину для определенного периода времени

Итак, давайте скажем, если machineA не отвечает (throwing RestClientException), я буду называть onFailure метод каждый раз и держать приращением счетчика, а затем, делая вызов machineA снова, я проверяю isBlocked метод, передавая machineA как имя хоста и 5 в качестве порогового значения, так что если machineA был заблокирован 5 раз, тогда я вообще не звоню им. Моя библиотека многопоточная, поэтому я использую volatile здесь, так как хочу, чтобы все потоки видели одинаковое значение.

Ниже то, что я имею в DataMapping классе:

public static volatile ConcurrentHashMap<String, AtomicInteger> blockedHosts = 
     new ConcurrentHashMap<String, AtomicInteger>(); 

boolean isBlocked(String hostname, int threshold) { 
    AtomicInteger count = blockedHosts.get(hostname); 
    return count != null && count.get() >= threshold; 
} 

void onFailure(String hostname) { 
    AtomicInteger newValue = new AtomicInteger(); 
    AtomicInteger val = blockedHosts.putIfAbsent(hostname, newValue); 
    // no need to care about over-reaching 5 here 
    (val == null ? newValue : val).incrementAndGet(); 
} 

void onSuccess(String hostname) { 
    blockedHosts.remove(hostname); 
} 

Постановка задачи: -

Теперь я хочу добавить еще одну функцию, которая - если machineA заблокирован (с момента его блокировки счетчика is> = 5), то я хочу, чтобы он блокировал для x интервала. У меня будет еще один параметр (key.getInterval()), который расскажет нам, как долго я хочу заблокировать этот компьютер и по истечении этого интервала, тогда только я начну звонить им. Я не могу понять, как добавить эту функцию?

Ниже приведен мой основной код темы, где я использую методы DataMapping, чтобы проверить, заблокировано ли имя хоста или нет, а также заблокировать имена хостов.

@Override 
public DataResponse call() { 
    ResponseEntity<String> response = null; 

    List<String> hostnames = some_code_here; 

    for (String hostname : hostnames) { 
     // If hostname is in block list, skip sending request to this host 
     if (DataMapping.isBlocked(hostname)) { 
      continue; 
     } 
     try { 
      String url = createURL(hostname); 
      response = restTemplate.exchange(url, HttpMethod.GET, key.getEntity(), String.class); 
      DataMapping.onSuccess(hostname); 

      // some code here to return the response if successful 
     } catch (RestClientException ex) { 
      // adding to block list 
      DataMapping.onFailure(hostname); 
     } 
    } 

    return new DataResponse(DataErrorEnum.SERVER_UNAVAILABLE, DataStatusEnum.ERROR);   
} 

Как я могу заблокировать конкретную машину в течение определенного периода времени, и как только этот интервал истек, то только начинаю звонить на них?

+0

Вы должны следить, когда он стал заблокирован для того, чтобы сказать, если интервал истекло, не только ли он заблокирован , –

ответ

1

Вы можете использовать ScheduledExecutorService и schedule сбрасывать счетчик после определенного таймаута.

Вы можете заявить об этом в вашем DataMapping классе:

private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // or perhaps the thread pool version ? 

И в вашем методе onFailure() вы можете решить, хотите ли вы сбросить или просто декремент счетчик после определенного времени:

void onFailure(String hostname) { 
    // you can use `computeIfAbsent` in java8 
    AtomicInteger val = blockedHosts.computeIfAbsent(hostname, key -> new AtomicInteger()); 
    int count = val.incrementAndGet(); 
    // the test here is `==` to make sure the task is scheduled only once 
    if (count == threshold) { 
     scheduler.schedule(() -> blockedHosts.remove(hostname), 5L, TimeUnit.MINUTES); // or you may choose to just decrement the counter 
    } 
} 

В качестве примечания стороны, нет причин делать blockedHostsvolatile. Эта ссылка никогда не меняется; он должен быть final; и, возможно, private.


В java7, приведенный выше код будет выглядеть следующим образом:

void onFailure(String hostname) { 
    AtomicInteger newValue = new AtomicInteger(); 
    AtomicInteger val = blockedHosts.putIfAbsent(hostname, newValue); 
    int count = (val == null ? newValue : val).incrementAndGet(); 
    // the test here is `==` to make sure the task is scheduled only once 
    if (count == threshold) { 
     scheduler.schedule(new Runnable() { 
      @Override public void run() { 
       blockedHosts.remove(hostname); // or you may choose to just decrement the counter 
      } 
     }, 5L, TimeUnit.MINUTES); 
    } 
} 
+0

К сожалению, я уже на Java 7, и я не могу перейти на Java 8. Как это будет выглядеть с Java 7? – john

+0

Практически то же самое, за исключением 'computeIfAbsent' и аккуратного синтаксиса лямбда.Вам нужно будет создать экземпляр 'Callable' (или' Runnable') и отправить его службе-исполнителю. –

+0

Можете ли вы обновить это предложение Java 7. Я все еще пытаюсь понять, что делает код выше. У меня будет несколько вопросов, как только я увижу на Java 7, чтобы убедиться, что я понимаю. – john