use of io.servicetalk.client.api.ServiceDiscovererEvent in project servicetalk by apple.
the class DefaultDnsClient method dnsSrvQuery.
@Override
public Publisher<Collection<ServiceDiscovererEvent<InetSocketAddress>>> dnsSrvQuery(final String serviceName) {
requireNonNull(serviceName);
return defer(() -> {
// State per subscribe requires defer so each subscribe gets independent state.
final Map<String, ARecordPublisher> aRecordMap = new HashMap<>(8);
final Map<InetSocketAddress, Integer> availableAddresses = srvFilterDuplicateEvents ? new HashMap<>(8) : emptyMap();
final DnsDiscoveryObserver discoveryObserver = newDiscoveryObserver(serviceName);
// inactive events if necessary.
return recoverWithInactiveEvents(new SrvRecordPublisher(serviceName, discoveryObserver), true).flatMapConcatIterable(identity()).flatMapMerge(srvEvent -> {
assertInEventloop();
if (AVAILABLE.equals(srvEvent.status())) {
return defer(() -> {
final ARecordPublisher aPublisher = new ARecordPublisher(srvEvent.address().hostName(), discoveryObserver);
final ARecordPublisher prevAPublisher = aRecordMap.putIfAbsent(srvEvent.address().hostName(), aPublisher);
if (prevAPublisher != null) {
return newDuplicateSrv(serviceName, srvEvent.address().hostName());
}
Publisher<? extends Collection<ServiceDiscovererEvent<InetAddress>>> returnPub = recoverWithInactiveEvents(aPublisher, false);
return srvFilterDuplicateEvents ? srvFilterDups(returnPub, availableAddresses, srvEvent.address().port()) : returnPub.map(events -> mapEventList(events, inetAddress -> new InetSocketAddress(inetAddress, srvEvent.address().port())));
}).retryWhen((i, cause) -> {
assertInEventloop();
// don't retry. Otherwise this is a resolution exception (e.g. UnknownHostException), and retry.
return cause == SrvAddressRemovedException.DNS_SRV_ADDR_REMOVED || aRecordMap.remove(srvEvent.address().hostName()) == null ? Completable.failed(cause) : srvHostNameRepeater.apply(i);
}).onErrorComplete();
} else if (srvEvent instanceof SrvInactiveEvent) {
// Unwrap the list so we can use it in SrvInactiveCombinerOperator below.
return from(((SrvInactiveEvent<HostAndPort, InetSocketAddress>) srvEvent).aggregatedEvents);
} else {
final ARecordPublisher aPublisher = aRecordMap.remove(srvEvent.address().hostName());
if (aPublisher != null) {
aPublisher.cancelAndFail0(SrvAddressRemovedException.DNS_SRV_ADDR_REMOVED);
}
return empty();
}
}, srvConcurrency).liftSync(inactiveEventsOnError ? SrvInactiveCombinerOperator.EMIT : SrvInactiveCombinerOperator.NO_EMIT);
});
}
use of io.servicetalk.client.api.ServiceDiscovererEvent in project servicetalk by apple.
the class DefaultDnsClientTest method preferIpv4ButOnlyAAAARecordIsPresent.
@ParameterizedTest(name = "missing-record-status={0}")
@MethodSource("missingRecordStatus")
void preferIpv4ButOnlyAAAARecordIsPresent(ServiceDiscovererEvent.Status missingRecordStatus) throws Exception {
setup(missingRecordStatus);
client.closeAsync().toFuture().get();
client = dnsClientBuilder(missingRecordStatus).dnsResolverAddressTypes(IPV4_PREFERRED).build();
final String ipv6 = nextIp6();
final String domain = "servicetalk.io";
recordStore.addIPv6Address(domain, DEFAULT_TTL, ipv6);
TestPublisherSubscriber<ServiceDiscovererEvent<InetAddress>> subscriber = dnsQuery(domain);
Subscription subscription = subscriber.awaitSubscription();
subscription.request(Long.MAX_VALUE);
assertEvent(subscriber.takeOnNext(), ipv6, AVAILABLE);
// Remove all ips
recordStore.removeIPv6Address(domain, DEFAULT_TTL, ipv6);
assertThat(subscriber.awaitOnError(), instanceOf(UnknownHostException.class));
}
use of io.servicetalk.client.api.ServiceDiscovererEvent in project servicetalk by apple.
the class DefaultDnsClientTest method srvCNAMEDuplicateAddresses.
private void srvCNAMEDuplicateAddresses(boolean inactiveEventsOnError, ServiceDiscovererEvent.Status missingRecordStatus) throws Exception {
client.closeAsync().toFuture().get();
client = dnsClientBuilder(missingRecordStatus).dnsServerAddressStreamProvider(new SequentialDnsServerAddressStreamProvider(dnsServer2.localAddress(), dnsServer.localAddress())).inactiveEventsOnError(inactiveEventsOnError).build();
final String domain = "sd.servicetalk.io";
final String srvCNAME = "sdcname.servicetalk.io";
final String targetDomain1 = "target1.mysvc.servicetalk.io";
final String targetDomain2 = "target2.mysvc.servicetalk.io";
final int targetPort = 9876;
final String ip1 = nextIp();
final String ip2 = nextIp();
final int ttl = DEFAULT_TTL + 10;
recordStore.addCNAME(domain, srvCNAME, ttl);
recordStore.addSrv(domain, targetDomain1, targetPort, ttl);
recordStore.addSrv(domain, targetDomain2, targetPort, ttl);
recordStore.addSrv(srvCNAME, targetDomain1, targetPort, 1);
recordStore.addSrv(srvCNAME, targetDomain2, targetPort, 1);
recordStore.addIPv4Address(targetDomain1, ttl, ip1);
recordStore.addIPv4Address(targetDomain2, ttl, ip2);
TestPublisherSubscriber<ServiceDiscovererEvent<InetSocketAddress>> subscriber = dnsSrvQuery(domain);
Subscription subscription = subscriber.awaitSubscription();
subscription.request(10);
List<ServiceDiscovererEvent<InetSocketAddress>> signals = subscriber.takeOnNext(2);
assertHasEvent(signals, ip1, targetPort, AVAILABLE);
assertHasEvent(signals, ip2, targetPort, AVAILABLE);
// Atomically remove all domain records.
recordStore.removeRecords(createCnameRecord(domain, srvCNAME, ttl), createSrvRecord(domain, targetDomain1, targetPort, ttl), createSrvRecord(domain, targetDomain2, targetPort, ttl));
if (inactiveEventsOnError) {
signals = subscriber.takeOnNext(2);
assertHasEvent(signals, ip1, targetPort, missingRecordStatus);
assertHasEvent(signals, ip2, targetPort, missingRecordStatus);
}
assertThat(subscriber.awaitOnError(), instanceOf(UnknownHostException.class));
}
use of io.servicetalk.client.api.ServiceDiscovererEvent in project servicetalk by apple.
the class DefaultDnsClientTest method multipleSrvMultipleADiscover.
@ParameterizedTest(name = "missing-record-status={0}")
@MethodSource("missingRecordStatus")
void multipleSrvMultipleADiscover(ServiceDiscovererEvent.Status missingRecordStatus) throws Exception {
setup(missingRecordStatus);
final String domain = "mysvc.apple.com";
final String targetDomain1 = "target1.mysvc.apple.com";
final String targetDomain2 = "target2.mysvc.apple.com";
final int targetPort1 = 9876;
final int targetPort2 = 9878;
final String ip1 = nextIp();
final String ip2 = nextIp();
final String ip3 = nextIp();
final String ip4 = nextIp();
recordStore.addSrv(domain, targetDomain1, targetPort1, DEFAULT_TTL);
recordStore.addSrv(domain, targetDomain2, targetPort2, DEFAULT_TTL);
recordStore.addIPv4Address(targetDomain1, DEFAULT_TTL, ip1, ip2);
recordStore.addIPv4Address(targetDomain2, DEFAULT_TTL, ip3, ip4);
TestPublisherSubscriber<ServiceDiscovererEvent<InetSocketAddress>> subscriber = dnsSrvQuery(domain);
Subscription subscription = subscriber.awaitSubscription();
subscription.request(4);
List<ServiceDiscovererEvent<InetSocketAddress>> signals = subscriber.takeOnNext(4);
assertHasEvent(signals, ip1, targetPort1, AVAILABLE);
assertHasEvent(signals, ip2, targetPort1, AVAILABLE);
assertHasEvent(signals, ip3, targetPort2, AVAILABLE);
assertHasEvent(signals, ip4, targetPort2, AVAILABLE);
}
use of io.servicetalk.client.api.ServiceDiscovererEvent in project servicetalk by apple.
the class DefaultDnsClientTest method multipleSrvSingleADiscover.
@ParameterizedTest(name = "missing-record-status={0}")
@MethodSource("missingRecordStatus")
void multipleSrvSingleADiscover(ServiceDiscovererEvent.Status missingRecordStatus) throws Exception {
setup(missingRecordStatus);
final String domain = "mysvc.apple.com";
final String targetDomain1 = "target1.mysvc.apple.com";
final String targetDomain2 = "target2.mysvc.apple.com";
final int targetPort1 = 9876;
final int targetPort2 = 9878;
final String ip1 = nextIp();
final String ip2 = nextIp();
recordStore.addSrv(domain, targetDomain1, targetPort1, DEFAULT_TTL);
recordStore.addSrv(domain, targetDomain2, targetPort2, DEFAULT_TTL);
recordStore.addIPv4Address(targetDomain1, DEFAULT_TTL, ip1);
recordStore.addIPv4Address(targetDomain2, DEFAULT_TTL, ip2);
TestPublisherSubscriber<ServiceDiscovererEvent<InetSocketAddress>> subscriber = dnsSrvQuery(domain);
Subscription subscription = subscriber.awaitSubscription();
subscription.request(2);
List<ServiceDiscovererEvent<InetSocketAddress>> signals = subscriber.takeOnNext(2);
assertHasEvent(signals, ip1, targetPort1, AVAILABLE);
assertHasEvent(signals, ip2, targetPort2, AVAILABLE);
}
Aggregations