Search in sources :

Example 1 with ServiceDiscovererEvent

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);
    });
}
Also used : EventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutor) CancelImmediatelySubscriber(io.servicetalk.concurrent.internal.CancelImmediatelySubscriber) LoggerFactory(org.slf4j.LoggerFactory) ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) Publisher.empty(io.servicetalk.concurrent.api.Publisher.empty) DefaultDnsQuestion(io.netty.handler.codec.dns.DefaultDnsQuestion) DefaultDnsCache(io.netty.resolver.dns.DefaultDnsCache) Collections.singletonList(java.util.Collections.singletonList) InetAddress(java.net.InetAddress) SubscriberUtils.newExceptionForInvalidRequestN(io.servicetalk.concurrent.internal.SubscriberUtils.newExceptionForInvalidRequestN) Duration(java.time.Duration) Map(java.util.Map) DnsClients.mapEventList(io.servicetalk.dns.discovery.netty.DnsClients.mapEventList) BuilderUtils.socketChannel(io.servicetalk.transport.netty.internal.BuilderUtils.socketChannel) SocketChannel(io.netty.channel.socket.SocketChannel) DnsDiscoveryObserver(io.servicetalk.dns.discovery.netty.DnsServiceDiscovererObserver.DnsDiscoveryObserver) DefaultDnsRecordDecoder.decodeName(io.netty.handler.codec.dns.DefaultDnsRecordDecoder.decodeName) DnsNameResolver(io.netty.resolver.dns.DnsNameResolver) FutureListener(io.netty.util.concurrent.FutureListener) SubscriberUtils.handleExceptionFromOnSubscribe(io.servicetalk.concurrent.internal.SubscriberUtils.handleExceptionFromOnSubscribe) Collections.emptyList(java.util.Collections.emptyList) Collection(java.util.Collection) ThrowableUtils.unknownStackTrace(io.servicetalk.concurrent.internal.ThrowableUtils.unknownStackTrace) DefaultServiceDiscovererEvent(io.servicetalk.client.api.DefaultServiceDiscovererEvent) EventLoop(io.netty.channel.EventLoop) InetSocketAddress(java.net.InetSocketAddress) List(java.util.List) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) DuplicateSubscribeException(io.servicetalk.concurrent.internal.DuplicateSubscribeException) Function.identity(java.util.function.Function.identity) ResolutionResult(io.servicetalk.dns.discovery.netty.DnsServiceDiscovererObserver.ResolutionResult) DnsRecord(io.netty.handler.codec.dns.DnsRecord) DnsNameResolverBuilder(io.netty.resolver.dns.DnsNameResolverBuilder) Publisher(io.servicetalk.concurrent.api.Publisher) NANOSECONDS(java.util.concurrent.TimeUnit.NANOSECONDS) ByteBuffer.wrap(java.nio.ByteBuffer.wrap) DnsRawRecord(io.netty.handler.codec.dns.DnsRawRecord) HashMap(java.util.HashMap) Cancellable(io.servicetalk.concurrent.Cancellable) DnsResolutionObserver(io.servicetalk.dns.discovery.netty.DnsServiceDiscovererObserver.DnsResolutionObserver) RepeatStrategies.repeatWithConstantBackoffDeltaJitter(io.servicetalk.concurrent.api.RepeatStrategies.repeatWithConstantBackoffDeltaJitter) Subscriber(io.servicetalk.concurrent.PublisherSource.Subscriber) ArrayList(java.util.ArrayList) RandomAccess(java.util.RandomAccess) BuilderUtils.datagramChannel(io.servicetalk.transport.netty.internal.BuilderUtils.datagramChannel) SubscribablePublisher(io.servicetalk.concurrent.api.internal.SubscribablePublisher) AVAILABLE(io.servicetalk.client.api.ServiceDiscovererEvent.Status.AVAILABLE) ByteBuf(io.netty.buffer.ByteBuf) ImmediateEventExecutor(io.netty.util.concurrent.ImmediateEventExecutor) SubscriberUtils.deliverErrorFromSource(io.servicetalk.concurrent.internal.SubscriberUtils.deliverErrorFromSource) ServiceDiscovererUtils.calculateDifference(io.servicetalk.dns.discovery.netty.ServiceDiscovererUtils.calculateDifference) SRV(io.netty.handler.codec.dns.DnsRecordType.SRV) Objects.requireNonNull(java.util.Objects.requireNonNull) Comparator.comparing(java.util.Comparator.comparing) Publisher.from(io.servicetalk.concurrent.api.Publisher.from) Publisher.defer(io.servicetalk.concurrent.api.Publisher.defer) SubscriberUtils.safeOnError(io.servicetalk.concurrent.internal.SubscriberUtils.safeOnError) Nullable(javax.annotation.Nullable) IntFunction(java.util.function.IntFunction) Collections.emptyMap(java.util.Collections.emptyMap) Logger(org.slf4j.Logger) SubscriberUtils.isRequestNValid(io.servicetalk.concurrent.internal.SubscriberUtils.isRequestNValid) Promise(io.netty.util.concurrent.Promise) EventLoopAwareNettyIoExecutors.toEventLoopAwareNettyIoExecutor(io.servicetalk.transport.netty.internal.EventLoopAwareNettyIoExecutors.toEventLoopAwareNettyIoExecutor) ListenableAsyncCloseable(io.servicetalk.concurrent.api.ListenableAsyncCloseable) ClosedChannelException(java.nio.channels.ClosedChannelException) FlowControlUtils.addWithOverflowProtection(io.servicetalk.concurrent.internal.FlowControlUtils.addWithOverflowProtection) Completable(io.servicetalk.concurrent.api.Completable) PublisherOperator(io.servicetalk.concurrent.api.PublisherOperator) AsyncCloseables.toAsyncCloseable(io.servicetalk.concurrent.api.AsyncCloseables.toAsyncCloseable) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) RejectedSubscribeError(io.servicetalk.concurrent.internal.RejectedSubscribeError) IoExecutor(io.servicetalk.transport.api.IoExecutor) Publisher.failed(io.servicetalk.concurrent.api.Publisher.failed) Completable.completed(io.servicetalk.concurrent.api.Completable.completed) ResolvedAddressTypes(io.netty.resolver.ResolvedAddressTypes) Future(io.netty.util.concurrent.Future) Comparator(java.util.Comparator) SECONDS(java.util.concurrent.TimeUnit.SECONDS) HostAndPort(io.servicetalk.transport.api.HostAndPort) DnsDiscoveryObserver(io.servicetalk.dns.discovery.netty.DnsServiceDiscovererObserver.DnsDiscoveryObserver) HashMap(java.util.HashMap) InetSocketAddress(java.net.InetSocketAddress) Publisher(io.servicetalk.concurrent.api.Publisher) SubscribablePublisher(io.servicetalk.concurrent.api.internal.SubscribablePublisher) HostAndPort(io.servicetalk.transport.api.HostAndPort) Collection(java.util.Collection) InetAddress(java.net.InetAddress)

Example 2 with ServiceDiscovererEvent

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));
}
Also used : ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) DefaultServiceDiscovererEvent(io.servicetalk.client.api.DefaultServiceDiscovererEvent) UnknownHostException(java.net.UnknownHostException) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 3 with ServiceDiscovererEvent

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));
}
Also used : ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) DefaultServiceDiscovererEvent(io.servicetalk.client.api.DefaultServiceDiscovererEvent) UnknownHostException(java.net.UnknownHostException) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription)

Example 4 with ServiceDiscovererEvent

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);
}
Also used : ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) DefaultServiceDiscovererEvent(io.servicetalk.client.api.DefaultServiceDiscovererEvent) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 5 with ServiceDiscovererEvent

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);
}
Also used : ServiceDiscovererEvent(io.servicetalk.client.api.ServiceDiscovererEvent) DefaultServiceDiscovererEvent(io.servicetalk.client.api.DefaultServiceDiscovererEvent) Subscription(io.servicetalk.concurrent.PublisherSource.Subscription) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Aggregations

ServiceDiscovererEvent (io.servicetalk.client.api.ServiceDiscovererEvent)28 DefaultServiceDiscovererEvent (io.servicetalk.client.api.DefaultServiceDiscovererEvent)27 Subscription (io.servicetalk.concurrent.PublisherSource.Subscription)24 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)20 MethodSource (org.junit.jupiter.params.provider.MethodSource)20 UnknownHostException (java.net.UnknownHostException)10 InetSocketAddress (java.net.InetSocketAddress)4 HostAndPort (io.servicetalk.transport.api.HostAndPort)2 ArrayList (java.util.ArrayList)2 Collection (java.util.Collection)2 ByteBuf (io.netty.buffer.ByteBuf)1 EventLoop (io.netty.channel.EventLoop)1 SocketChannel (io.netty.channel.socket.SocketChannel)1 DefaultDnsQuestion (io.netty.handler.codec.dns.DefaultDnsQuestion)1 DefaultDnsRecordDecoder.decodeName (io.netty.handler.codec.dns.DefaultDnsRecordDecoder.decodeName)1 DnsRawRecord (io.netty.handler.codec.dns.DnsRawRecord)1 DnsRecord (io.netty.handler.codec.dns.DnsRecord)1 SRV (io.netty.handler.codec.dns.DnsRecordType.SRV)1 ResolvedAddressTypes (io.netty.resolver.ResolvedAddressTypes)1 DefaultDnsCache (io.netty.resolver.dns.DefaultDnsCache)1