1

以下に示すように、複数のスレッドによって呼び出されるコードで Callable を使用しています。今のところ、何かRestClientExceptionがスローされるたびhostnameに、blockList に追加しています。

public class Task implements Callable<DataResponse> {

    private DataKey key;
    private RestTemplate restTemplate;

    public Task(DataKey key, RestTemplate restTemplate) {
        this.key = key;
        this.restTemplate = restTemplate;
    }

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

        // construct what are the hostnames I can call basis on user id
        List<String> hostnames = some_code_here;

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

                // some code here to return the response if successful
            } catch (HttpClientErrorException ex) {
                // log exception
                return new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
            } catch (HttpServerErrorException ex) {
                // log exception
                return new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
            } catch (RestClientException ex) {
                // I don't want to add it to block list instantly.
                // If same hostname as failed five times consecutively, then only add it
                DataMapping.blockHost(hostname);
            }
        }

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

以下は私がDataMappingクラスで持っているものです:

private static final AtomicReference<ConcurrentHashMap<String, String>> blockedHosts = 
        new AtomicReference<ConcurrentHashMap<String, String>>(new ConcurrentHashMap<String, String>());

public static boolean isBlocked(String hostName) {
    return blockedHosts.get().containsKey(hostName);
}

public static void blockHost(String hostName) {
    blockedHosts.get().put(hostName, hostName);
}

問題文:-

メソッドでわかるように、スローされるとすぐcallにブロックしていますが、これは正しくない可能性があります。特定のものが5 回連続してスローされたかどうかを確認する必要があります。次に、この行を呼び出してこれを blockList に追加するだけです。それ以外の場合は、blockList に追加しないでください。hostnameRestClientExceptionhostnameRestClientExceptionhostnameDataMapping.blockHost(hostname);

これを行うための最も効率的で最良の方法は何ですか? 最大で、合計で 70 ~ 100 台の固有のマシンを用意します。

hostnameこの場合、call メソッドは複数のスレッドから呼び出されるため、それぞれが をスローした場合に備えて、それぞれのカウントを適切に維持する必要がありますRestClientException

編集:

DataMappingクラスにも以下のメソッドがあります。

ホスト名が実際にブロックされているかどうかに関係なく、サービスが実際のデータを提供するため、セット全体を置き換える 2 分ごとに実行されるバックグラウンド スレッドがあります。atomic referenceそして、セット全体を交換するときは、 for が必要だと思います。

2分後にどのマシンがブロックされているかを知る必要があるため、コードにブロック機能をローカルに追加しています。

// this is being updated from my background thread which runs every 2 minutes
public static void replaceBlockedHosts(List<String> hostNames) {
    ConcurrentHashMap<String, String> newBlockedHosts = new ConcurrentHashMap<>();
    for (String hostName : hostNames) {
        newBlockedHosts.put(hostName, hostName);
    }
    blockedHosts.set(newBlockedHosts);
}
4

2 に答える 2

0

クラスで- のような静的レジスタを維持public static ConcurrentHashMap<String, Integer> toBeBlockedHostName = new ConcurrentHashMap<String, Integer>();しますDataMapping。そして、次のように FOR ループを使用します。

  for (String hostname : hostnames) {

        // .. some code here
        //After ensuring everything is success and no RestClientException, i.e. can be last line of your TRY block...
        DataMapping.toBeBlockedHostName.remove("stackoverflow6361");
        catch (RestClientException ex) {
            if(DataMapping.toBeBlockedHostName.get("stackoverflow6361") == null){
                DataMapping.toBeBlockedHostName.put("stackoverflow6361", new Integer(1));
            } else{
                if(DataMapping.toBeBlockedHostName.get("stackoverflow6361") == 5){ //Don't hard code 5, have it from some property file after defining as retryThreshold...
                    System.out.println("Blocking threshold reached, block the hostname...");
                    DataMapping.blockHost(hostname);
                } else{
                    DataMapping.toBeBlockedHostName.put("stackoverflow6361", (toBeBlockedHostName.get("stackoverflow6361") + 1));
                }
            }
        }

注意: :ConcurrentHashMapすべての操作はスレッドセーフですが、検索操作はロックを必要としません。

5 回連続して再試行に失敗すると、ホスト名がブロックされますが、再度ブロック解除する場合は、レジスタをクリアする必要があることに注意してください。

PS: HashMap に適切なゲッターとセッターを用意してください。

于 2015-06-06T19:22:35.720 に答える