0

私は自分のサービスに Http 呼び出しを行うライブラリに取り組んでおり、サービス マシンが応答しない場合 (ソケット タイムアウトまたは接続タイムアウトがある場合)、それらをローカルに追加し、blockListマシンが 5 回ブロックされている場合は、彼らに電話しないでください。

machineAが応答していない場合 、毎回メソッド(throwing RestClientException)を呼び出しonFailureてカウンターをインクリメントし続け、再度呼び出しを行うときに、ホスト名と 5 をしきい値として渡してメソッドmachineAをチェックするので、 5 回ブロックされている場合は作成しません。彼らに電話してください。私のライブラリはマルチスレッドなので、すべてのスレッドに同じ値を表示させたいので、ここで volatile を使用しています。isBlockedmachineAmachineA

以下は私が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);
}

問題文:-

ここで、もう 1 つの機能を追加したいと思います。つまり、ブロックされている場合machineA(ブロック数が 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);        
}

特定のマシンを特定の期間ブロックし、その間隔が経過するとすぐに、それらのマシンへの呼び出しのみを開始するにはどうすればよいですか?

4

1 に答える 1

1

ScheduledExecutorServiceschedule、特定のタイムアウト後のカウンターのリセットを使用できます。

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

ちなみに、作る理由はありませんblockedHosts volatile。その参照は決して変わりません。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);
    }
}
于 2016-05-16T00:07:28.833 に答える