com.gs.api.accelrx.web.client.servicediscovery.AccelRxWebServiceDiscovery Maven / Gradle / Ivy
package com.gs.api.accelrx.web.client.servicediscovery;
import com.gs.api.accelrx.AccelRxWebClientServiceDiscovery;
import com.gs.api.accelrx.WebClientEndpoint;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.ServiceDiscoveryEndpoint;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.ServiceDiscoveryEndpointPolicy;
import com.gs.api.accelrx.web.client.servicediscovery.endpoint.WeightedRoundRobinEndpointPolicy;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Single;
import io.vertx.core.http.HttpMethod;
import io.vertx.rxjava3.core.MultiMap;
import io.vertx.rxjava3.core.Vertx;
import io.vertx.rxjava3.servicediscovery.ServiceDiscovery;
import io.vertx.servicediscovery.Record;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class AccelRxWebServiceDiscovery implements AccelRxWebClientServiceDiscovery {
private static final Logger log = LoggerFactory.getLogger(AccelRxWebServiceDiscovery.class);
private final String serviceName;
private final ServiceDiscovery serviceDiscovery;
private final ServiceDiscoveryEndpointPolicy policy;
private AccelRxServiceImporter serviceImporter;
private Set currentRecordIds;
protected List records;
private AccelRxWebServiceDiscovery(Vertx vertx, String serviceName) {
this.serviceDiscovery = ServiceDiscovery.create(vertx);
this.serviceName = serviceName;
this.policy = new WeightedRoundRobinEndpointPolicy();
}
public static AccelRxWebServiceDiscovery create(Vertx vertx, String serviceName) {
return new AccelRxWebServiceDiscovery(vertx, serviceName);
}
public Completable registerServiceImporter(AccelRxServiceImporter serviceImporter) {
log.info("Initialising Service Discovery Registry");
if (serviceImporter != null) {
this.serviceImporter = serviceImporter;
return serviceImporter.register(serviceDiscovery);
} else {
return Completable.complete();
}
}
@Override
public Completable refresh() {
return serviceImporter.refresh()
.andThen(Completable.fromAction(policy::reset));
}
@Override
public Maybe extends WebClientEndpoint> endpoint(HttpMethod method, String path, MultiMap headers, MultiMap queryParams) {
return records()
.filter(records -> !records.isEmpty())
.map(records -> selectEndpoint(records, method, path, headers, queryParams))
.map(selectedEndpoint -> ServiceDiscoveryEndpoint.create(selectedEndpoint.service(), selectedEndpoint.instance(), selectedEndpoint.isSsl(), selectedEndpoint.host(), selectedEndpoint.port(), selectedEndpoint.pathPrefix(), path))
.doOnSuccess(endpoint -> log.info("Selected endpoint {}", endpoint));
}
private ServiceDiscoveryEndpoint selectEndpoint(List records, HttpMethod method, String path, MultiMap headers, MultiMap queryParams) {
Map> matchingRecordsByOrder = records.stream()
.filter(record -> record.matches(method, path, headers, queryParams))
.collect(Collectors.groupingBy(ServiceDiscoveryRecord::order));
int minOrder = matchingRecordsByOrder.keySet().stream()
.mapToInt(order -> order)
.min()
.orElseThrow();
List matchingRecords = matchingRecordsByOrder.get(minOrder);
if (matchingRecords.size() == 0) {
throw new RuntimeException("Service discovery found no matching endpoints");
} else if (matchingRecords.size() == 1) {
return matchingRecords.get(0).endpoint();
} else {
return policy.select(matchingRecords).endpoint();
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AccelRxWebServiceDiscovery that = (AccelRxWebServiceDiscovery) o;
return records.equals(that.records);
}
@Override
public int hashCode() {
return Objects.hash(records);
}
private Single> records() {
return serviceDiscovery.rxGetRecords(record -> record.getName().equals(serviceName))
.filter(this::needsRefresh)
.map(records -> records.stream()
.map(ServiceDiscoveryRecord::fromRecord)
.collect(Collectors.toList()))
.map(newRecords -> {
this.records = newRecords;
return newRecords;
})
.switchIfEmpty(Single.fromCallable(() -> this.records));
}
boolean needsRefresh(List records) {
Set newRecordIds = records.stream()
.map(Record::getRegistration)
.collect(Collectors.toSet());
if (currentRecordIds == null || !currentRecordIds.equals(newRecordIds)) {
currentRecordIds = newRecordIds;
return true;
} else {
return false;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy