¿Cómo seguir el principio de responsabilidad única en mi ejecutor HttpClient?
estoy usandoRestTemplate
como miHttpClient
ejecutar URL y el servidor devolverá una cadena json como respuesta. El cliente llamará a esta biblioteca pasandoDataKey
objeto que tieneuserId
en eso.
userId
, Averiguaré cuáles son las máquinas que puedo golpear para obtener los datos y luego almacenar esas máquinas en unLinkedList
, para poder ejecutarlos secuencialmente.Después de eso, comprobaré si el primer nombre de host está en la lista de bloqueo o no. Si no está allí en la lista de bloqueo, crearé una URL con el primer nombre de host en la lista y la ejecutaré, y si la respuesta es exitosa, regresaré la respuesta. Pero digamos que si ese primer nombre de host está en la lista de bloqueo, entonces intentaré obtener el segundo nombre de host en la lista y hacer la url y ejecutarla, así que básicamente,primero encuentre el nombre de host que no está en la lista de bloqueo antes de hacer la URL.Ahora, digamos que si seleccionamos el primer nombre de host que no estaba en la lista de bloqueo y ejecutamos la URL y de alguna manera el servidor estaba inactivo o no respondía, entonces ejecutaré el segundo nombre de host en la lista y seguiré haciendo esto hasta que obtenga una respuesta exitosa.Pero asegúrese de que no estén en la lista de bloqueo también, así que debemos seguir el punto anterior.Si todos los servidores están inactivos o en la lista de bloqueo, entonces simplemente puedo iniciar sesión y devolver el error de que el servicio no está disponible.A continuación se muestra mi clase de DataClient que será llamada por el cliente y pasaránDataKey
oponerse agetData
método.
public class DataClient implements Client {
private RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
private ExecutorService service = Executors.newFixedThreadPool(15);
public Future<DataResponse> getData(DataKey key) {
DataExecutorTask task = new DataExecutorTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
}
A continuación se muestra mi clase DataExecutorTask:
public class DataExecutorTask implements Callable<DataResponse> {
private DataKey key;
private RestTemplate restTemplate;
public DataExecutorTask(DataKey key, RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.key = key;
}
@Override
public DataResponse call() {
DataResponse dataResponse = null;
ResponseEntity<String> response = null;
MappingsHolder mappings = ShardMappings.getMappings(key.getTypeOfFlow());
// given a userId, find all the hostnames
// it can also have four hostname or one hostname or six hostname as well in the list
List<String> hostnames = mappings.getListOfHostnames(key.getUserId());
for (String hostname : hostnames) {
// If host name is null or host name is in local block list, skip sending request to this host
if (ClientUtils.isEmpty(hostname) || ShardMappings.isBlockHost(hostname)) {
continue;
}
try {
String url = generateURL(hostname);
response = restTemplate.exchange(url, HttpMethod.GET, key.getEntity(), String.class);
if (response.getStatusCode() == HttpStatus.NO_CONTENT) {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.NO_CONTENT,
DataStatusEnum.SUCCESS);
} else {
dataResponse = new DataResponse(response.getBody(), DataErrorEnum.OK,
DataStatusEnum.SUCCESS);
}
break;
// below codes are duplicated looks like
} catch (HttpClientErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
return dataResponse;
} catch (HttpServerErrorException ex) {
HttpStatusCodeException httpException = (HttpStatusCodeException) ex;
DataErrorEnum error = DataErrorEnum.getErrorEnumByException(httpException);
String errorMessage = httpException.getResponseBodyAsString();
dataResponse = new DataResponse(errorMessage, error, DataStatusEnum.ERROR);
return dataResponse;
} catch (RestClientException ex) {
// if it comes here, then it means some of the servers are down so adding it into block list
ShardMappings.blockHost(hostname);
}
}
if (ClientUtils.isEmpty(hostnames)) {
dataResponse = new DataResponse(null, DataErrorEnum.PERT_ERROR, DataStatusEnum.ERROR);
} else if (response == null) { // either all the servers are down or all the servers were in block list
dataResponse = new DataResponse(null, DataErrorEnum.SERVICE_UNAVAILABLE, DataStatusEnum.ERROR);
}
return dataResponse;
}
}
Mi lista de bloqueo sigue actualizándose desde otro hilo de fondo cada 1 minuto. Si algún servidor está inactivo y no responde, entonces necesito bloquear ese servidor usando esto:
ShardMappings.blockHost(hostname);
Y para verificar si algún servidor está en la lista de bloqueo o no, utilizo esto:
ShardMappings.isBlockHost(hostname);
yo estoy volviendoSERVICE_UNAVAILABLE
si los servidores están inactivos o en la lista de bloqueo, sobre la base deresponse == null
cheque,No estoy seguro si es un enfoque correcto o no.
No estoy siguiendo el Principio de Responsabilidad Única aquí, supongo. ¿Alguien puede dar un ejemplo de cuál es la mejor manera de utilizar el principio SRP aquí?
Después de pensar mucho, pude extraer la clase de hosts como se muestra a continuación, pero no estoy seguro¿Cuál es la mejor manera de usar esto en mi anterior DataExecutorTask
clase.
public class Hosts {
private final LinkedList<String> hostsnames = new LinkedList<String>();
public Hosts(final List<String> hosts) {
checkNotNull(hosts, "hosts cannot be null");
this.hostsnames.addAll(hosts);
}
public Optional<String> getNextAvailableHostname() {
while (!hostsnames.isEmpty()) {
String firstHostname = hostsnames.removeFirst();
if (!ClientUtils.isEmpty(firstHostname) && !ShardMappings.isBlockHost(firstHostname)) {
return Optional.of(firstHostname);
}
}
return Optional.absent();
}
public boolean isEmpty() {
return hostsnames.isEmpty();
}
}