use of com.couchbase.client.core.error.ConfigException in project couchbase-jvm-clients by couchbase.
the class DefaultConfigurationProvider method loadAndRefreshGlobalConfig.
@Override
public Mono<Void> loadAndRefreshGlobalConfig() {
return Mono.defer(() -> {
if (!shutdown.get()) {
globalConfigLoadInProgress = true;
boolean tls = core.context().environment().securityConfig().tlsEnabled();
int kvPort = tls ? DEFAULT_KV_TLS_PORT : DEFAULT_KV_PORT;
final AtomicBoolean hasErrored = new AtomicBoolean();
return Flux.range(1, Math.min(MAX_PARALLEL_LOADERS, currentSeedNodes().size())).flatMap(index -> Flux.fromIterable(currentSeedNodes()).take(Math.min(index, currentSeedNodes().size())).last().flatMap(seed -> {
long start = System.nanoTime();
if (!currentSeedNodes().contains(seed)) {
// node we are about to load is still part of the list.
return Mono.empty();
}
NodeIdentifier identifier = new NodeIdentifier(seed.address(), seed.clusterManagerPort().orElse(DEFAULT_MANAGER_PORT));
return globalLoader.load(identifier, seed.kvPort().orElse(kvPort)).doOnError(throwable -> core.context().environment().eventBus().publish(new IndividualGlobalConfigLoadFailedEvent(Duration.ofNanos(System.nanoTime() - start), core.context(), throwable, seed.address())));
}).retryWhen(Retry.from(companion -> companion.flatMap(rs -> {
Throwable f = rs.failure();
if (shutdown.get()) {
return Mono.error(new AlreadyShutdownException());
}
if (f instanceof UnsupportedConfigMechanismException) {
return Mono.error(Exceptions.propagate(f));
}
Duration delay = Duration.ofMillis(1);
eventBus.publish(new GlobalConfigRetriedEvent(delay, core.context(), f));
return Mono.just(rs.totalRetries()).delayElement(delay, core.context().environment().scheduler());
}))).onErrorResume(throwable -> {
if (hasErrored.compareAndSet(false, true)) {
return Mono.error(throwable);
}
return Mono.empty();
})).take(1).switchIfEmpty(Mono.error(new ConfigException("Could not locate a single global configuration"))).map(ctx -> {
proposeGlobalConfig(ctx);
return ctx;
}).then(globalRefresher.start()).doOnTerminate(() -> globalConfigLoadInProgress = false);
} else {
return Mono.error(new AlreadyShutdownException());
}
});
}
use of com.couchbase.client.core.error.ConfigException in project couchbase-jvm-clients by couchbase.
the class Core method initGlobalConfig.
/**
* Instructs the client to, if possible, load and initialize the global config.
*
* <p>Since global configs are an "optional" feature depending on the cluster version, if an error happens
* this method will not fail. Rather it will log the exception (with some logic dependent on the type of error)
* and will allow the higher level components to move on where possible.</p>
*/
@Stability.Internal
public void initGlobalConfig() {
long start = System.nanoTime();
configurationProvider.loadAndRefreshGlobalConfig().subscribe(v -> {
}, throwable -> {
InitGlobalConfigFailedEvent.Reason reason = InitGlobalConfigFailedEvent.Reason.UNKNOWN;
if (throwable instanceof UnsupportedConfigMechanismException) {
reason = InitGlobalConfigFailedEvent.Reason.UNSUPPORTED;
} else if (throwable instanceof GlobalConfigNotFoundException) {
reason = InitGlobalConfigFailedEvent.Reason.NO_CONFIG_FOUND;
} else if (throwable instanceof ConfigException) {
if (throwable.getCause() instanceof RequestCanceledException) {
RequestContext ctx = ((RequestCanceledException) throwable.getCause()).context().requestContext();
if (ctx.request().cancellationReason() == CancellationReason.SHUTDOWN) {
reason = InitGlobalConfigFailedEvent.Reason.SHUTDOWN;
}
} else if (throwable.getMessage().contains("NO_ACCESS")) {
reason = InitGlobalConfigFailedEvent.Reason.NO_ACCESS;
}
} else if (throwable instanceof AlreadyShutdownException) {
reason = InitGlobalConfigFailedEvent.Reason.SHUTDOWN;
}
eventBus.publish(new InitGlobalConfigFailedEvent(reason.severity(), Duration.ofNanos(System.nanoTime() - start), context(), reason, throwable));
});
}
use of com.couchbase.client.core.error.ConfigException in project couchbase-jvm-clients by couchbase.
the class DefaultConfigurationProviderIntegrationTest method retriesOnBucketNotFoundDuringLoadException.
/**
* Need to make sure that if a bucket is not found during load, we continue retrying the open
* bucket attempts.
*/
@Test
@IgnoreWhen(clusterTypes = ClusterType.CAVES)
void retriesOnBucketNotFoundDuringLoadException() {
TestNodeConfig cfg = config().firstNodeWith(Services.KV).get();
Set<SeedNode> seeds = new HashSet<>(Collections.singletonList(SeedNode.create(cfg.hostname(), Optional.of(cfg.ports().get(Services.KV)), Optional.of(cfg.ports().get(Services.MANAGER)))));
SimpleEventBus eventBus = new SimpleEventBus(true);
environment = CoreEnvironment.builder().eventBus(eventBus).build();
core = Core.create(environment, authenticator(), seeds);
ConfigurationProvider provider = new DefaultConfigurationProvider(core, seeds);
try {
String bucketName = "this-bucket-does-not-exist";
provider.openBucket(bucketName).subscribe(v -> {
}, e -> assertTrue(e instanceof ConfigException));
waitUntilCondition(() -> eventBus.publishedEvents().stream().anyMatch(p -> p instanceof BucketOpenRetriedEvent));
for (Event event : eventBus.publishedEvents()) {
if (event instanceof BucketOpenRetriedEvent) {
assertEquals(bucketName, ((BucketOpenRetriedEvent) event).bucketName());
assertTrue(event.cause() instanceof BucketNotFoundDuringLoadException);
}
}
} finally {
provider.shutdown().block();
}
}
use of com.couchbase.client.core.error.ConfigException in project couchbase-jvm-clients by couchbase.
the class CouchbaseBucketConfig method buildPartitionHosts.
/**
* Helper method to reference the partition hosts from the raw node list.
*
* @param nodeInfos the node infos.
* @param partitionInfo the partition info.
* @return a ordered reference list for the partition hosts.
*/
private static List<NodeInfo> buildPartitionHosts(List<NodeInfo> nodeInfos, PartitionInfo partitionInfo) {
List<NodeInfo> partitionHosts = new ArrayList<>();
for (String rawHost : partitionInfo.partitionHosts()) {
String convertedHost;
int directPort;
try {
String[] parts = rawHost.split(":");
String host = "";
String port = parts[parts.length - 1];
if (parts.length > 2) {
// Handle IPv6 syntax
for (int i = 0; i < parts.length - 1; i++) {
host += parts[i];
if (parts[i].endsWith("]")) {
break;
} else {
host += ":";
}
}
if (host.startsWith("[") && host.endsWith("]")) {
host = host.substring(1, host.length() - 1);
}
if (host.endsWith(":")) {
host = host.substring(0, host.length() - 1);
}
} else {
// Simple IPv4 Handling
host = parts[0];
}
convertedHost = host;
try {
directPort = Integer.parseInt(port);
} catch (NumberFormatException e) {
// TODO: LOGGER.warn("Could not parse port from the node address: {}, fallback to 0", system(rawHost));
directPort = 0;
}
} catch (Exception e) {
throw new ConfigException("Could not resolve " + rawHost + "on config building.", e);
}
for (NodeInfo nodeInfo : nodeInfos) {
// Make sure we only take into account nodes which contain KV
if (!nodeInfo.services().containsKey(ServiceType.KV)) {
continue;
}
if (nodeInfo.hostname().equals(convertedHost) && (nodeInfo.services().get(ServiceType.KV) == directPort || directPort == 0)) {
partitionHosts.add(nodeInfo);
}
}
}
if (partitionHosts.size() != partitionInfo.partitionHosts().length) {
throw new ConfigException("Partition size is not equal after conversion, this is a bug.");
}
return partitionHosts;
}
use of com.couchbase.client.core.error.ConfigException in project couchbase-jvm-clients by couchbase.
the class DefaultConfigurationProvider method openBucket.
@Override
public Mono<Void> openBucket(final String name) {
return Mono.defer(() -> {
if (!shutdown.get()) {
bucketConfigLoadInProgress.incrementAndGet();
boolean tls = core.context().environment().securityConfig().tlsEnabled();
int kvPort = tls ? DEFAULT_KV_TLS_PORT : DEFAULT_KV_PORT;
int managerPort = tls ? DEFAULT_MANAGER_TLS_PORT : DEFAULT_MANAGER_PORT;
final Optional<String> alternate = core.context().alternateAddress();
return Flux.range(1, Math.min(MAX_PARALLEL_LOADERS, currentSeedNodes().size())).flatMap(index -> Flux.fromIterable(currentSeedNodes()).take(Math.min(index, currentSeedNodes().size())).last().flatMap(seed -> {
NodeIdentifier identifier = new NodeIdentifier(seed.address(), seed.clusterManagerPort().orElse(DEFAULT_MANAGER_PORT));
final AtomicReference<Map<ServiceType, Integer>> alternatePorts = new AtomicReference<>();
final Optional<String> alternateAddress = alternate.map(a -> mapAlternateAddress(a, seed, tls, alternatePorts));
final int mappedKvPort;
final int mappedManagerPort;
if (alternateAddress.isPresent()) {
Map<ServiceType, Integer> ports = alternatePorts.get();
mappedKvPort = ports.get(ServiceType.KV);
mappedManagerPort = ports.get(ServiceType.MANAGER);
} else {
mappedKvPort = seed.kvPort().orElse(kvPort);
mappedManagerPort = seed.clusterManagerPort().orElse(managerPort);
}
return loadBucketConfigForSeed(identifier, mappedKvPort, mappedManagerPort, name, alternateAddress);
}).retryWhen(Retry.from(companion -> companion.flatMap(rs -> {
final Throwable f = rs.failure();
if (shutdown.get()) {
return Mono.error(new AlreadyShutdownException());
}
if (f instanceof UnsupportedConfigMechanismException) {
return Mono.error(Exceptions.propagate(f));
}
boolean bucketNotFound = f instanceof BucketNotFoundDuringLoadException;
boolean bucketNotReady = f instanceof BucketNotReadyDuringLoadException;
// For bucket not found or not ready wait a bit longer, retry the rest quickly
Duration delay = bucketNotFound || bucketNotReady ? Duration.ofMillis(500) : Duration.ofMillis(1);
eventBus.publish(new BucketOpenRetriedEvent(name, delay, core.context(), f));
return Mono.just(rs.totalRetries()).delayElement(delay, core.context().environment().scheduler());
})))).take(1).switchIfEmpty(Mono.error(new ConfigException("Could not locate a single bucket configuration for bucket: " + name))).map(ctx -> {
proposeBucketConfig(ctx);
return ctx;
}).then(registerRefresher(name)).doOnTerminate(bucketConfigLoadInProgress::decrementAndGet).onErrorResume(t -> closeBucketIgnoreShutdown(name).then(Mono.error(t)));
} else {
return Mono.error(new AlreadyShutdownException());
}
});
}
Aggregations