¿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.

Usando lo dadouserId, 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&nbsp;si los servidores están inactivos o en la lista de bloqueo, sobre la base deresponse == null&nbsp;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();
    }
}