use of com.couchbase.client.core.cnc.events.config.BucketConfigRefreshFailedEvent in project couchbase-jvm-clients by couchbase.
the class KeyValueBucketRefresher method filterEligibleNodes.
/**
* Helper method to generate a stream of KV nodes that can be used to fetch a config.
*
* <p>To be more resilient to failures, this method (similar to 1.x) shifts the node
* list on each invocation by one to make sure we hit all of them eventually.</p>
*
* @param name the bucket name.
* @return a flux of nodes that have the KV service enabled.
*/
private Flux<NodeInfo> filterEligibleNodes(final String name) {
return Flux.defer(() -> {
BucketConfig config = provider.config().bucketConfig(name);
if (config == null) {
eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.KV, BucketConfigRefreshFailedEvent.Reason.NO_BUCKET_FOUND, Optional.empty()));
return Flux.empty();
}
List<NodeInfo> nodes = new ArrayList<>(config.nodes());
shiftNodeList(nodes);
return Flux.fromIterable(nodes).filter(n -> n.services().containsKey(ServiceType.KV) || n.sslServices().containsKey(ServiceType.KV)).take(MAX_PARALLEL_FETCH);
});
}
use of com.couchbase.client.core.cnc.events.config.BucketConfigRefreshFailedEvent in project couchbase-jvm-clients by couchbase.
the class ClusterManagerBucketRefresher method registerStream.
/**
* Registers the given bucket name with the http stream.
*
* <p>Note that this method deliberately subscribes "out of band" and not being flatMapped into the
* {@link #register(String)} return value. The idea is that the flux config subscription keeps on going
* forever until specifically unsubscribed through either {@link #deregister(String)} or {@link #shutdown()}.</p>
*
* @param ctx the core context to use.
* @param name the name of the bucket.
* @return once registered, returns the disposable so it can be later used to deregister.
*/
private Disposable registerStream(final CoreContext ctx, final String name) {
return Mono.defer(() -> {
BucketConfigStreamingRequest request = new BucketConfigStreamingRequest(ctx.environment().timeoutConfig().managementTimeout(), ctx, BestEffortRetryStrategy.INSTANCE, name, ctx.authenticator());
core.send(request);
return Reactor.wrap(request, request.response(), true);
}).flux().flatMap(res -> {
if (res.status().success()) {
return res.configs().map(config -> new ProposedBucketConfigContext(name, config, res.address()));
} else {
eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.MANAGER, BucketConfigRefreshFailedEvent.Reason.INDIVIDUAL_REQUEST_FAILED, Optional.of(res)));
// and retry the whole thing
return Flux.error(new ConfigException());
}
}).doOnError(e -> eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.MANAGER, BucketConfigRefreshFailedEvent.Reason.STREAM_FAILED, Optional.of(e)))).doOnComplete(() -> {
eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.MANAGER, BucketConfigRefreshFailedEvent.Reason.STREAM_CLOSED, Optional.empty()));
// handled in the retryWhen below.
throw new ConfigException();
}).retryWhen(Retry.any().exponentialBackoff(Duration.ofMillis(32), Duration.ofMillis(4096)).toReactorRetry()).subscribe(provider::proposeBucketConfig);
}
use of com.couchbase.client.core.cnc.events.config.BucketConfigRefreshFailedEvent in project couchbase-jvm-clients by couchbase.
the class KeyValueBucketRefresher method fetchConfigPerNode.
/**
* Helper method to fetch a config per node provided.
*
* <p>Note that the bucket config request sent here has a fail fast strategy, so that if nodes are offline they
* do not circle the system forever (given they have a specific node target). Since the refresher polls every
* fixed interval anyways, fresh requests will flood the system eventually and there is no point in keeping
* the old ones around.</p>
*
* <p>Also, the timeout is set to the poll interval since it does not make sense to keep them around any
* longer.</p>
*
* @param name the bucket name.
* @param nodes the flux of nodes that can be used to fetch a config.
* @return returns configs for each node if found.
*/
private Flux<ProposedBucketConfigContext> fetchConfigPerNode(final String name, final Flux<NodeInfo> nodes) {
return nodes.flatMap(nodeInfo -> {
CoreContext ctx = core.context();
CarrierBucketConfigRequest request = new CarrierBucketConfigRequest(configRequestTimeout, ctx, new CollectionIdentifier(name, Optional.empty(), Optional.empty()), FailFastRetryStrategy.INSTANCE, nodeInfo.identifier());
core.send(request);
return Reactor.wrap(request, request.response(), true).filter(response -> {
if (!response.status().success()) {
eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.KV, BucketConfigRefreshFailedEvent.Reason.INDIVIDUAL_REQUEST_FAILED, Optional.of(response)));
}
return response.status().success();
}).map(response -> new ProposedBucketConfigContext(name, new String(response.content(), UTF_8), nodeInfo.hostname())).onErrorResume(t -> {
eventBus.publish(new BucketConfigRefreshFailedEvent(core.context(), BucketConfigRefreshFailedEvent.RefresherType.KV, BucketConfigRefreshFailedEvent.Reason.INDIVIDUAL_REQUEST_FAILED, Optional.of(t)));
return Mono.empty();
});
});
}
Aggregations