mirror of https://github.com/grpc/grpc-java.git
core: channelBuilder.defaulServiceConfig() and lookUpServiceConfig()
This commit is contained in:
parent
185cf3d047
commit
1735adc4c0
|
|
@ -18,8 +18,10 @@ package io.grpc;
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ManagedChannelBuilder} that delegates all its builder method to another builder by
|
* A {@link ManagedChannelBuilder} that delegates all its builder method to another builder by
|
||||||
|
|
@ -242,6 +244,18 @@ public abstract class ForwardingChannelBuilder<T extends ForwardingChannelBuilde
|
||||||
return thisT();
|
return thisT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T defaultServiceConfig(@Nullable Map<String, ?> serviceConfig) {
|
||||||
|
delegate().defaultServiceConfig(serviceConfig);
|
||||||
|
return thisT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T lookUpServiceConfig(boolean enable) {
|
||||||
|
delegate().lookUpServiceConfig(enable);
|
||||||
|
return thisT();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link ManagedChannel} built by the delegate by default. Overriding method can
|
* Returns the {@link ManagedChannel} built by the delegate by default. Overriding method can
|
||||||
* return different value.
|
* return different value.
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@ package io.grpc;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for {@link ManagedChannel} instances.
|
* A builder for {@link ManagedChannel} instances.
|
||||||
|
|
@ -537,6 +539,60 @@ public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>>
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a service config to the channel. The channel will use the default service config when
|
||||||
|
* the name resolver provides no service config or if the channel disables lookup service config
|
||||||
|
* from name resolver (see {@link #lookUpServiceConfig(boolean)}). The argument
|
||||||
|
* {@code serviceConfig} is a nested map representing a Json object in the most natural way:
|
||||||
|
*
|
||||||
|
* <table border="1">
|
||||||
|
* <tr>
|
||||||
|
* <td>Json entry</td><td>Java Type</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>object</td><td>{@link Map}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>array</td><td>{@link List}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>string</td><td>{@link String}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>number</td><td>{@link Double}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>boolean</td><td>{@link Boolean}</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td>null</td><td>{@code null}</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
* <p>If null is passed, then there will be no default service config.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException When the given serviceConfig is invalid or the current version
|
||||||
|
* of grpc library can not parse it gracefully. The state of the builder is unchanged if
|
||||||
|
* an exception is thrown.
|
||||||
|
* @return this
|
||||||
|
* @since 1.20.0
|
||||||
|
*/
|
||||||
|
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/5189")
|
||||||
|
public T defaultServiceConfig(@Nullable Map<String, ?> serviceConfig) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables service config look-up from the naming system. Enabled by default.
|
||||||
|
*
|
||||||
|
* @return this
|
||||||
|
* @since 1.20.0
|
||||||
|
*/
|
||||||
|
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/5189")
|
||||||
|
public T lookUpServiceConfig(boolean enable) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a channel using the given parameters.
|
* Builds a channel using the given parameters.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
@ -139,6 +141,10 @@ public abstract class AbstractManagedChannelImplBuilder
|
||||||
InternalChannelz channelz = InternalChannelz.instance();
|
InternalChannelz channelz = InternalChannelz.instance();
|
||||||
int maxTraceEvents;
|
int maxTraceEvents;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
Map<String, ?> defaultServiceConfig;
|
||||||
|
boolean lookUpServiceConfig = true;
|
||||||
|
|
||||||
protected TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
|
protected TransportTracer.Factory transportTracerFactory = TransportTracer.getDefaultFactory();
|
||||||
|
|
||||||
private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
private int maxInboundMessageSize = GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
||||||
|
|
@ -379,6 +385,78 @@ public abstract class AbstractManagedChannelImplBuilder
|
||||||
return thisT();
|
return thisT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T defaultServiceConfig(@Nullable Map<String, ?> serviceConfig) {
|
||||||
|
// TODO(notcarl): use real parsing
|
||||||
|
defaultServiceConfig = checkMapEntryTypes(serviceConfig);
|
||||||
|
return thisT();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static Map<String, ?> checkMapEntryTypes(@Nullable Map<?, ?> map) {
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// Not using ImmutableMap.Builder because of extra guava dependency for Android.
|
||||||
|
Map<String, Object> parsedMap = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
||||||
|
checkArgument(
|
||||||
|
entry.getKey() instanceof String,
|
||||||
|
"The key of the entry '%s' is not of String type", entry);
|
||||||
|
|
||||||
|
String key = (String) entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value == null) {
|
||||||
|
parsedMap.put(key, null);
|
||||||
|
} else if (value instanceof Map) {
|
||||||
|
parsedMap.put(key, checkMapEntryTypes((Map<?, ?>) value));
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
parsedMap.put(key, checkListEntryTypes((List<?>) value));
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
parsedMap.put(key, value);
|
||||||
|
} else if (value instanceof Double) {
|
||||||
|
parsedMap.put(key, value);
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
parsedMap.put(key, value);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The value of the map entry '" + entry + "' is of type '" + value.getClass()
|
||||||
|
+ "', which is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableMap(parsedMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<?> checkListEntryTypes(List<?> list) {
|
||||||
|
List<Object> parsedList = new ArrayList<>(list.size());
|
||||||
|
for (Object value : list) {
|
||||||
|
if (value == null) {
|
||||||
|
parsedList.add(null);
|
||||||
|
} else if (value instanceof Map) {
|
||||||
|
parsedList.add(checkMapEntryTypes((Map<?, ?>) value));
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
parsedList.add(checkListEntryTypes((List<?>) value));
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
parsedList.add(value);
|
||||||
|
} else if (value instanceof Double) {
|
||||||
|
parsedList.add(value);
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
parsedList.add(value);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"The entry '" + value + "' is of type '" + value.getClass()
|
||||||
|
+ "', which is not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableList(parsedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T lookUpServiceConfig(boolean enable) {
|
||||||
|
this.lookUpServiceConfig = enable;
|
||||||
|
return thisT();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable or enable stats features. Enabled by default.
|
* Disable or enable stats features. Enabled by default.
|
||||||
*
|
*
|
||||||
|
|
@ -490,7 +568,7 @@ public abstract class AbstractManagedChannelImplBuilder
|
||||||
/**
|
/**
|
||||||
* Subclasses can override this method to provide a default port to {@link NameResolver} for use
|
* Subclasses can override this method to provide a default port to {@link NameResolver} for use
|
||||||
* in cases where the target string doesn't include a port. The default implementation returns
|
* in cases where the target string doesn't include a port. The default implementation returns
|
||||||
* {@link GrpcUtil.DEFAULT_PORT_SSL}.
|
* {@link GrpcUtil#DEFAULT_PORT_SSL}.
|
||||||
*/
|
*/
|
||||||
protected int getDefaultPort() {
|
protected int getDefaultPort() {
|
||||||
return GrpcUtil.DEFAULT_PORT_SSL;
|
return GrpcUtil.DEFAULT_PORT_SSL;
|
||||||
|
|
|
||||||
|
|
@ -237,9 +237,17 @@ final class ManagedChannelImpl extends ManagedChannel implements
|
||||||
// Must be mutated and read from syncContext
|
// Must be mutated and read from syncContext
|
||||||
@CheckForNull
|
@CheckForNull
|
||||||
private Boolean haveBackends; // a flag for doing channel tracing when flipped
|
private Boolean haveBackends; // a flag for doing channel tracing when flipped
|
||||||
// Must be mutated and read from syncContext
|
// Must be mutated and read from constructor or syncContext
|
||||||
|
// TODO(notcarl): check this value when error in service config resolution
|
||||||
@Nullable
|
@Nullable
|
||||||
private Map<String, ?> lastServiceConfig; // used for channel tracing when value changed
|
private Map<String, ?> lastServiceConfig; // used for channel tracing when value changed
|
||||||
|
@Nullable
|
||||||
|
private final Map<String, ?> defaultServiceConfig;
|
||||||
|
// Must be mutated and read from constructor or syncContext
|
||||||
|
// See service config error handling spec for reference.
|
||||||
|
// TODO(notcarl): check this value when error in service config resolution
|
||||||
|
private boolean waitingForServiceConfig = true;
|
||||||
|
private final boolean lookUpServiceConfig;
|
||||||
|
|
||||||
// One instance per channel.
|
// One instance per channel.
|
||||||
private final ChannelBufferMeter channelBufferUsed = new ChannelBufferMeter();
|
private final ChannelBufferMeter channelBufferUsed = new ChannelBufferMeter();
|
||||||
|
|
@ -581,6 +589,9 @@ final class ManagedChannelImpl extends ManagedChannel implements
|
||||||
|
|
||||||
serviceConfigInterceptor = new ServiceConfigInterceptor(
|
serviceConfigInterceptor = new ServiceConfigInterceptor(
|
||||||
retryEnabled, builder.maxRetryAttempts, builder.maxHedgedAttempts);
|
retryEnabled, builder.maxRetryAttempts, builder.maxHedgedAttempts);
|
||||||
|
this.defaultServiceConfig = builder.defaultServiceConfig;
|
||||||
|
this.lastServiceConfig = defaultServiceConfig;
|
||||||
|
this.lookUpServiceConfig = builder.lookUpServiceConfig;
|
||||||
Channel channel = new RealChannel(nameResolver.getServiceAuthority());
|
Channel channel = new RealChannel(nameResolver.getServiceAuthority());
|
||||||
channel = ClientInterceptors.intercept(channel, serviceConfigInterceptor);
|
channel = ClientInterceptors.intercept(channel, serviceConfigInterceptor);
|
||||||
if (builder.binlog != null) {
|
if (builder.binlog != null) {
|
||||||
|
|
@ -621,6 +632,23 @@ final class ManagedChannelImpl extends ManagedChannel implements
|
||||||
channelCallTracer = callTracerFactory.create();
|
channelCallTracer = callTracerFactory.create();
|
||||||
this.channelz = checkNotNull(builder.channelz);
|
this.channelz = checkNotNull(builder.channelz);
|
||||||
channelz.addRootChannel(this);
|
channelz.addRootChannel(this);
|
||||||
|
|
||||||
|
if (!lookUpServiceConfig) {
|
||||||
|
if (defaultServiceConfig != null) {
|
||||||
|
channelLogger.log(
|
||||||
|
ChannelLogLevel.INFO, "Service config look-up disabled, using default service config");
|
||||||
|
}
|
||||||
|
handleServiceConfigUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// May only be called in constructor or syncContext
|
||||||
|
private void handleServiceConfigUpdate() {
|
||||||
|
waitingForServiceConfig = false;
|
||||||
|
serviceConfigInterceptor.handleUpdate(lastServiceConfig);
|
||||||
|
if (retryEnabled) {
|
||||||
|
throttle = ServiceConfigUtil.getThrottlePolicy(lastServiceConfig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
@ -1278,32 +1306,57 @@ final class ManagedChannelImpl extends ManagedChannel implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAddresses(final List<EquivalentAddressGroup> servers, final Attributes config) {
|
public void onAddresses(final List<EquivalentAddressGroup> servers, final Attributes attrs) {
|
||||||
final class NamesResolved implements Runnable {
|
final class NamesResolved implements Runnable {
|
||||||
|
|
||||||
|
@SuppressWarnings("ReferenceEquality")
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
channelLogger.log(
|
channelLogger.log(
|
||||||
ChannelLogLevel.DEBUG, "Resolved address: {0}, config={1}", servers, config);
|
ChannelLogLevel.DEBUG, "Resolved address: {0}, config={1}", servers, attrs);
|
||||||
|
|
||||||
if (haveBackends == null || !haveBackends) {
|
if (haveBackends == null || !haveBackends) {
|
||||||
channelLogger.log(ChannelLogLevel.INFO, "Address resolved: {0}", servers);
|
channelLogger.log(ChannelLogLevel.INFO, "Address resolved: {0}", servers);
|
||||||
haveBackends = true;
|
haveBackends = true;
|
||||||
}
|
}
|
||||||
final Map<String, ?> serviceConfig =
|
|
||||||
config.get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG);
|
|
||||||
if (serviceConfig != null && !serviceConfig.equals(lastServiceConfig)) {
|
|
||||||
channelLogger.log(ChannelLogLevel.INFO, "Service config changed");
|
|
||||||
lastServiceConfig = serviceConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
nameResolverBackoffPolicy = null;
|
nameResolverBackoffPolicy = null;
|
||||||
|
|
||||||
|
// Assuming no error in config resolution for now.
|
||||||
|
final Map<String, ?> serviceConfig =
|
||||||
|
attrs.get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG);
|
||||||
|
Map<String, ?> effectiveServiceConfig;
|
||||||
|
if (!lookUpServiceConfig) {
|
||||||
if (serviceConfig != null) {
|
if (serviceConfig != null) {
|
||||||
try {
|
channelLogger.log(
|
||||||
serviceConfigInterceptor.handleUpdate(serviceConfig);
|
ChannelLogLevel.INFO,
|
||||||
if (retryEnabled) {
|
"Service config from name resolver discarded by channel settings");
|
||||||
throttle = ServiceConfigUtil.getThrottlePolicy(serviceConfig);
|
|
||||||
}
|
}
|
||||||
|
effectiveServiceConfig = defaultServiceConfig;
|
||||||
|
} else {
|
||||||
|
// Try to use config if returned from name resolver
|
||||||
|
// Otherwise, try to use the default config if available
|
||||||
|
if (serviceConfig != null) {
|
||||||
|
effectiveServiceConfig = serviceConfig;
|
||||||
|
} else {
|
||||||
|
effectiveServiceConfig = defaultServiceConfig;
|
||||||
|
if (defaultServiceConfig != null) {
|
||||||
|
channelLogger.log(
|
||||||
|
ChannelLogLevel.INFO,
|
||||||
|
"Received no service config, using default service config");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(notcarl): reference equality is not right (although not harmful) right now.
|
||||||
|
// Name resolver should return the same config if txt record is the same
|
||||||
|
if (effectiveServiceConfig != lastServiceConfig) {
|
||||||
|
channelLogger.log(ChannelLogLevel.INFO,
|
||||||
|
"Service config changed{0}", effectiveServiceConfig == null ? " to null" : "");
|
||||||
|
lastServiceConfig = effectiveServiceConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
handleServiceConfigUpdate();
|
||||||
} catch (RuntimeException re) {
|
} catch (RuntimeException re) {
|
||||||
logger.log(
|
logger.log(
|
||||||
Level.WARNING,
|
Level.WARNING,
|
||||||
|
|
@ -1318,7 +1371,13 @@ final class ManagedChannelImpl extends ManagedChannel implements
|
||||||
handleErrorInSyncContext(Status.UNAVAILABLE.withDescription(
|
handleErrorInSyncContext(Status.UNAVAILABLE.withDescription(
|
||||||
"Name resolver " + resolver + " returned an empty list"));
|
"Name resolver " + resolver + " returned an empty list"));
|
||||||
} else {
|
} else {
|
||||||
helper.lb.handleResolvedAddressGroups(servers, config);
|
Attributes effectiveAttrs = attrs;
|
||||||
|
if (effectiveServiceConfig != serviceConfig) {
|
||||||
|
effectiveAttrs = attrs.toBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, effectiveServiceConfig)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
helper.lb.handleResolvedAddressGroups(servers, effectiveAttrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,12 @@ import io.grpc.ClientInterceptor;
|
||||||
import io.grpc.Deadline;
|
import io.grpc.Deadline;
|
||||||
import io.grpc.MethodDescriptor;
|
import io.grpc.MethodDescriptor;
|
||||||
import io.grpc.internal.ManagedChannelServiceConfig.MethodInfo;
|
import io.grpc.internal.ManagedChannelServiceConfig.MethodInfo;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import javax.annotation.CheckForNull;
|
import javax.annotation.CheckForNull;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies RPCs in conformance with a Service Config.
|
* Modifies RPCs in conformance with a Service Config.
|
||||||
|
|
@ -47,7 +48,7 @@ final class ServiceConfigInterceptor implements ClientInterceptor {
|
||||||
private final int maxHedgedAttemptsLimit;
|
private final int maxHedgedAttemptsLimit;
|
||||||
|
|
||||||
// Setting this to true and observing this equal to true are run in different threads.
|
// Setting this to true and observing this equal to true are run in different threads.
|
||||||
private volatile boolean nameResolveComplete;
|
private volatile boolean initComplete;
|
||||||
|
|
||||||
ServiceConfigInterceptor(
|
ServiceConfigInterceptor(
|
||||||
boolean retryEnabled, int maxRetryAttemptsLimit, int maxHedgedAttemptsLimit) {
|
boolean retryEnabled, int maxRetryAttemptsLimit, int maxHedgedAttemptsLimit) {
|
||||||
|
|
@ -56,11 +57,17 @@ final class ServiceConfigInterceptor implements ClientInterceptor {
|
||||||
this.maxHedgedAttemptsLimit = maxHedgedAttemptsLimit;
|
this.maxHedgedAttemptsLimit = maxHedgedAttemptsLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUpdate(@Nonnull Map<String, ?> serviceConfig) {
|
void handleUpdate(@Nullable Map<String, ?> serviceConfig) {
|
||||||
ManagedChannelServiceConfig conf = ManagedChannelServiceConfig.fromServiceConfig(
|
ManagedChannelServiceConfig conf;
|
||||||
|
if (serviceConfig == null) {
|
||||||
|
conf = new ManagedChannelServiceConfig(
|
||||||
|
new HashMap<String, MethodInfo>(), new HashMap<String, MethodInfo>());
|
||||||
|
} else {
|
||||||
|
conf = ManagedChannelServiceConfig.fromServiceConfig(
|
||||||
serviceConfig, retryEnabled, maxRetryAttemptsLimit, maxHedgedAttemptsLimit);
|
serviceConfig, retryEnabled, maxRetryAttemptsLimit, maxHedgedAttemptsLimit);
|
||||||
|
}
|
||||||
managedChannelServiceConfig.set(conf);
|
managedChannelServiceConfig.set(conf);
|
||||||
nameResolveComplete = true;
|
initComplete = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static final CallOptions.Key<RetryPolicy.Provider> RETRY_POLICY_KEY =
|
static final CallOptions.Key<RetryPolicy.Provider> RETRY_POLICY_KEY =
|
||||||
|
|
@ -72,7 +79,7 @@ final class ServiceConfigInterceptor implements ClientInterceptor {
|
||||||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
|
||||||
final MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
final MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
|
||||||
if (retryEnabled) {
|
if (retryEnabled) {
|
||||||
if (nameResolveComplete) {
|
if (initComplete) {
|
||||||
final RetryPolicy retryPolicy = getRetryPolicyFromConfig(method);
|
final RetryPolicy retryPolicy = getRetryPolicyFromConfig(method);
|
||||||
final class ImmediateRetryPolicyProvider implements RetryPolicy.Provider {
|
final class ImmediateRetryPolicyProvider implements RetryPolicy.Provider {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -106,7 +113,7 @@ final class ServiceConfigInterceptor implements ClientInterceptor {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public RetryPolicy get() {
|
public RetryPolicy get() {
|
||||||
if (!nameResolveComplete) {
|
if (!initComplete) {
|
||||||
return RetryPolicy.DEFAULT;
|
return RetryPolicy.DEFAULT;
|
||||||
}
|
}
|
||||||
return getRetryPolicyFromConfig(method);
|
return getRetryPolicyFromConfig(method);
|
||||||
|
|
@ -122,7 +129,7 @@ final class ServiceConfigInterceptor implements ClientInterceptor {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public HedgingPolicy get() {
|
public HedgingPolicy get() {
|
||||||
if (!nameResolveComplete) {
|
if (!initComplete) {
|
||||||
return HedgingPolicy.DEFAULT;
|
return HedgingPolicy.DEFAULT;
|
||||||
}
|
}
|
||||||
HedgingPolicy hedgingPolicy = getHedgingPolicyFromConfig(method);
|
HedgingPolicy hedgingPolicy = getHedgingPolicyFromConfig(method);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,11 @@ import io.grpc.internal.testing.StatsTestUtils.FakeTagger;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
|
@ -429,6 +433,70 @@ public class AbstractManagedChannelImplBuilderTest {
|
||||||
assertFalse(builder.retryEnabled);
|
assertFalse(builder.retryEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultServiceConfig_nullKey() {
|
||||||
|
Builder builder = new Builder("target");
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
config.put(null, "val");
|
||||||
|
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
builder.defaultServiceConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultServiceConfig_intKey() {
|
||||||
|
Builder builder = new Builder("target");
|
||||||
|
Map<Integer, Object> subConfig = new HashMap<>();
|
||||||
|
subConfig.put(3, "val");
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
config.put("key", subConfig);
|
||||||
|
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
builder.defaultServiceConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultServiceConfig_intValue() {
|
||||||
|
Builder builder = new Builder("target");
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
config.put("key", 3);
|
||||||
|
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
builder.defaultServiceConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultServiceConfig_nested() {
|
||||||
|
Builder builder = new Builder("target");
|
||||||
|
Map<String, Object> config = new HashMap<>();
|
||||||
|
List<Object> list1 = new ArrayList<>();
|
||||||
|
list1.add(123D);
|
||||||
|
list1.add(null);
|
||||||
|
list1.add(true);
|
||||||
|
list1.add("str");
|
||||||
|
Map<String, Object> map2 = new HashMap<>();
|
||||||
|
map2.put("key2", false);
|
||||||
|
map2.put("key3", null);
|
||||||
|
map2.put("key4", Collections.singletonList("v4"));
|
||||||
|
map2.put("key4", 3.14D);
|
||||||
|
map2.put("key5", new HashMap<String, Object>());
|
||||||
|
list1.add(map2);
|
||||||
|
config.put("key1", list1);
|
||||||
|
|
||||||
|
builder.defaultServiceConfig(config);
|
||||||
|
|
||||||
|
assertThat(builder.defaultServiceConfig).containsExactlyEntriesIn(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableNameResolverServiceConfig() {
|
||||||
|
Builder builder = new Builder("target");
|
||||||
|
assertThat(builder.lookUpServiceConfig).isTrue();
|
||||||
|
|
||||||
|
builder.lookUpServiceConfig(false);
|
||||||
|
assertThat(builder.lookUpServiceConfig).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
static class Builder extends AbstractManagedChannelImplBuilder<Builder> {
|
static class Builder extends AbstractManagedChannelImplBuilder<Builder> {
|
||||||
Builder(String target) {
|
Builder(String target) {
|
||||||
super(target);
|
super(target);
|
||||||
|
|
|
||||||
|
|
@ -3433,6 +3433,271 @@ public class ManagedChannelImplTest {
|
||||||
assertThat(coe.getError().getCause()).isInstanceOf(ClassCastException.class);
|
assertThat(coe.getError().getCause()).isInstanceOf(ClassCastException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableServiceConfigLookUp_noDefaultConfig() throws Exception {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
channelBuilder.lookUpServiceConfig(false);
|
||||||
|
|
||||||
|
Map<String, Object> serviceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
Attributes serviceConfigAttrs =
|
||||||
|
Attributes.newBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig)
|
||||||
|
.build();
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isNull();
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void disableServiceConfigLookUp_withDefaultConfig() throws Exception {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
channelBuilder.lookUpServiceConfig(false);
|
||||||
|
Map<String, Object> defaultServiceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
channelBuilder.defaultServiceConfig(defaultServiceConfig);
|
||||||
|
|
||||||
|
Map<String, Object> serviceConfig = new HashMap<>();
|
||||||
|
Attributes serviceConfigAttrs =
|
||||||
|
Attributes.newBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig)
|
||||||
|
.build();
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isEqualTo(defaultServiceConfig);
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableServiceConfigLookUp_noDefaultConfig() throws Exception {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
|
||||||
|
Map<String, Object> serviceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
Attributes serviceConfigAttrs =
|
||||||
|
Attributes.newBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig)
|
||||||
|
.build();
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isEqualTo(serviceConfig);
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
|
||||||
|
// new config
|
||||||
|
serviceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":false}]}");
|
||||||
|
serviceConfigAttrs =
|
||||||
|
Attributes.newBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig)
|
||||||
|
.build();
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
nameResolverFactory.allResolved();
|
||||||
|
|
||||||
|
attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer, times(2)).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isEqualTo(serviceConfig);
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableServiceConfigLookUp_withDefaultConfig() throws Exception {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
Map<String, Object> defaultServiceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
channelBuilder.defaultServiceConfig(defaultServiceConfig);
|
||||||
|
|
||||||
|
Map<String, Object> serviceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService2\"}],"
|
||||||
|
+ "\"waitForReady\":false}]}");
|
||||||
|
Attributes serviceConfigAttrs =
|
||||||
|
Attributes.newBuilder()
|
||||||
|
.set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, serviceConfig)
|
||||||
|
.build();
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isEqualTo(serviceConfig);
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableServiceConfigLookUp_resolverReturnsNoConfig_withDefaultConfig()
|
||||||
|
throws Exception {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
Map<String, Object> defaultServiceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
channelBuilder.defaultServiceConfig(defaultServiceConfig);
|
||||||
|
|
||||||
|
Attributes serviceConfigAttrs = Attributes.EMPTY;
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isEqualTo(defaultServiceConfig);
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void enableServiceConfigLookUp_resolverReturnsNoConfig_noDefaultConfig() {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().register(mockLoadBalancerProvider);
|
||||||
|
try {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
|
||||||
|
Attributes serviceConfigAttrs = Attributes.EMPTY;
|
||||||
|
nameResolverFactory.nextResolvedAttributes.set(serviceConfigAttrs);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
|
||||||
|
verify(mockLoadBalancer).handleResolvedAddressGroups(
|
||||||
|
eq(ImmutableList.of(addressGroup)),
|
||||||
|
attributesCaptor.capture());
|
||||||
|
assertThat(attributesCaptor.getValue().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG))
|
||||||
|
.isNull();
|
||||||
|
verify(mockLoadBalancer, never()).handleNameResolutionError(any(Status.class));
|
||||||
|
} finally {
|
||||||
|
LoadBalancerRegistry.getDefaultRegistry().deregister(mockLoadBalancerProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void useDefaultImmediatelyIfDisableLookUp() throws Exception {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
channelBuilder.lookUpServiceConfig(false);
|
||||||
|
Map<String, Object> defaultServiceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
channelBuilder.defaultServiceConfig(defaultServiceConfig);
|
||||||
|
requestConnection = false;
|
||||||
|
channelBuilder.maxTraceEvents(10);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
|
||||||
|
int size = getStats(channel).channelTrace.events.size();
|
||||||
|
assertThat(getStats(channel).channelTrace.events.get(size - 1))
|
||||||
|
.isEqualTo(new ChannelTrace.Event.Builder()
|
||||||
|
.setDescription("Service config look-up disabled, using default service config")
|
||||||
|
.setSeverity(ChannelTrace.Event.Severity.CT_INFO)
|
||||||
|
.setTimestampNanos(timer.getTicker().read())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void notUseDefaultImmediatelyIfEnableLookUp() throws Exception {
|
||||||
|
FakeNameResolverFactory nameResolverFactory =
|
||||||
|
new FakeNameResolverFactory.Builder(expectedUri)
|
||||||
|
.setServers(ImmutableList.of(addressGroup)).build();
|
||||||
|
channelBuilder.nameResolverFactory(nameResolverFactory);
|
||||||
|
channelBuilder.lookUpServiceConfig(true);
|
||||||
|
Map<String, Object> defaultServiceConfig =
|
||||||
|
parseConfig("{\"methodConfig\":[{"
|
||||||
|
+ "\"name\":[{\"service\":\"SimpleService1\"}],"
|
||||||
|
+ "\"waitForReady\":true}]}");
|
||||||
|
channelBuilder.defaultServiceConfig(defaultServiceConfig);
|
||||||
|
requestConnection = false;
|
||||||
|
channelBuilder.maxTraceEvents(10);
|
||||||
|
|
||||||
|
createChannel();
|
||||||
|
|
||||||
|
int size = getStats(channel).channelTrace.events.size();
|
||||||
|
assertThat(getStats(channel).channelTrace.events.get(size - 1))
|
||||||
|
.isNotEqualTo(new ChannelTrace.Event.Builder()
|
||||||
|
.setDescription("Using default service config")
|
||||||
|
.setSeverity(ChannelTrace.Event.Severity.CT_INFO)
|
||||||
|
.setTimestampNanos(timer.getTicker().read())
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
private static final class ChannelBuilder
|
private static final class ChannelBuilder
|
||||||
extends AbstractManagedChannelImplBuilder<ChannelBuilder> {
|
extends AbstractManagedChannelImplBuilder<ChannelBuilder> {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,21 @@ public class ServiceConfigInterceptorTest {
|
||||||
assertThat(callOptionsCap.getValue().isWaitForReady()).isTrue();
|
assertThat(callOptionsCap.getValue().isWaitForReady()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handleNullConfig() {
|
||||||
|
JsonObj name = new JsonObj("service", "service");
|
||||||
|
JsonObj methodConfig = new JsonObj("name", new JsonList(name), "waitForReady", true);
|
||||||
|
JsonObj serviceConfig = new JsonObj("methodConfig", new JsonList(methodConfig));
|
||||||
|
|
||||||
|
interceptor.handleUpdate(serviceConfig);
|
||||||
|
interceptor.handleUpdate(null);
|
||||||
|
|
||||||
|
interceptor.interceptCall(methodDescriptor, CallOptions.DEFAULT.withoutWaitForReady(), channel);
|
||||||
|
|
||||||
|
verify(channel).newCall(eq(methodDescriptor), callOptionsCap.capture());
|
||||||
|
assertThat(callOptionsCap.getValue().isWaitForReady()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleUpdateNotCalledBeforeInterceptCall() {
|
public void handleUpdateNotCalledBeforeInterceptCall() {
|
||||||
interceptor.interceptCall(methodDescriptor, CallOptions.DEFAULT.withoutWaitForReady(), channel);
|
interceptor.interceptCall(methodDescriptor, CallOptions.DEFAULT.withoutWaitForReady(), channel);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue