I am working on a project in which I construct a URL with a valid hostname (but not a blocked hostname) and then execute that URL using RestTemplate
from my main thread. I also have a single background thread in my application which parses the data from the URL and extracts the block list of hostnames from it.
If any block list of hostnames is present, then I won't make a call to that hostname from the main thread and I will try making a call to another hostname. By block list, I mean whenever any server is down, its hostname is on the block list.
Here is my background thread code. It will get the data from my service URL and keep on running every 10 minutes once my application has started up. It will then parse the data coming from the URL and store it in a ClientData
class variable.
public class TempScheduler {
// .. scheduledexecutors service code to start the background thread
// call the service and get the data and then parse
// the response.
private void callServiceURL() {
String url = "url";
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(url, String.class);
parseResponse(response);
}
// parse the response and store it in a variable
private void parseResponse(String response) {
//...
// get the block list of hostnames
Map<String, List<String>> coloExceptionList = gson.fromJson(response.split("blocklist=")[1], Map.class);
List<String> blockList = new ArrayList<String>();
for(Map.Entry<String, List<String>> entry : coloExceptionList.entrySet()) {
for(String hosts : entry.getValue()) {
blockList.add(hosts);
}
}
// store the block list of hostnames which I am not supposed to make a call
// from my main application
ClientData.replaceBlockedHosts(blockList);
}
}
Here is my ClientData
class in which I am using CountDownLatch
:
public class ClientData {
// do I need this AtomicReference with ConcurrentHashMap?
private static final AtomicReference<ConcurrentHashMap<String, String>> blockedHosts = new AtomicReference<>(
new ConcurrentHashMap<String, String>());
public static boolean isHostBlocked(String hostName) {
return blockedHosts.get().containsKey(hostName);
}
public static void blockHost(String hostName) {
blockedHosts.get().put(hostName, hostName);
}
public static void unblockHost(String hostName) {
blockedHosts.get().remove(hostName);
}
public static void replaceBlockedHosts(List<String> hostNames) {
ConcurrentHashMap<String, String> newBlockedHosts = new ConcurrentHashMap<>();
for (String hostName : hostNames) {
newBlockedHosts.put(hostName, hostName);
}
blockedHosts.set(newBlockedHosts);
}
}
And here is my main application thread code in which I am finding all the hostnames on which I can make a call and then iterate the hostnames
list to make a call.
If that hostname
is null
or in the block list category, then I won't make a call to that particular hostname and will try next hostname in the list.
@Override
public DataResponse call() throws Exception {
List<String> hostnames = new LinkedList<String>();
// .. some code here
for (String hostname : hostnames) {
// If host name is null or host name is in block list category, skip sending request to this host
if (hostname == null || ClientData.isHostBlocked(hostname)) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.getForObject(url, String.class);
break;
} catch (RestClientException ex) {
// log exception
ClientData.blockHost(hostname);
}
}
}
I don't need to make a call to the hostname whenever it is down from the main thread. And my background thread gets these detail from one of my service, whenever any server is down, it will have the list of hostnames and whenever they are up, that list will get updated.
The above Callable
code will be called at a rate of 1000 requests per second
so it has to be fast. For the first time, whenever my blockListOfHosts
is being updated from the background thread, I can return false instead of blocking the call using CountDownLatch
but it has to be atomic, all the threads should see correct value of the block list of hostnames.
And also, whenever any RestClientException
is being thrown, I will add that hostname in the blockListOfHosts
as well since my background thread is running every 10 minutes, so that list won't have this hostname until 10 minutes is done. And whenever this server came back up, my background will update this list automatically.
Does my ClientData
class looks right with the way I am using AtomicReference
or not?