Java Code Examples for io.vertx.core.Future#compose()

The following examples show how to use io.vertx.core.Future#compose() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ValidationHandlerImpl.java    From vertx-web with Apache License 2.0 7 votes vote down vote up
private Future<Map<String, RequestParameter>> processParams(Map<String, RequestParameter> parsedParams, Map<String, List<String>> params, ParameterProcessor[] processors) {
  Future<Map<String, RequestParameter>> waitingFutureChain = Future.succeededFuture(parsedParams);

  for (ParameterProcessor processor : processors) {
    try {
      Future<RequestParameter> fut = processor.process(params);
      if (fut.isComplete()) {
        if (fut.succeeded()) {
          parsedParams.put(processor.getName(), fut.result());
        } else if (fut.failed()) {
          return Future.failedFuture(fut.cause());
        }
      } else {
        waitingFutureChain = waitingFutureChain.compose(m -> fut.map(rp -> {
          parsedParams.put(processor.getName(), rp);
          return parsedParams;
        }));
      }
    } catch (BadRequestException e) {
      return Future.failedFuture(e);
    }
  }

  return waitingFutureChain;
}
 
Example 2
Source File: MainVerticle.java    From okapi with Apache License 2.0 6 votes vote down vote up
@Override
public void start(Promise<Void> promise) {
  Future<Void> fut = startDatabases();
  if (initMode == InitMode.NORMAL) {
    fut = fut.compose(x -> startModmanager());
    fut = fut.compose(x -> startTenants());
    fut = fut.compose(x -> checkInternalModules());
    fut = fut.compose(x -> startEnv());
    fut = fut.compose(x -> startDiscovery());
    fut = fut.compose(x -> startDeployment());
    fut = fut.compose(x -> startListening());
    fut = fut.compose(x -> startRedeploy());
  }
  fut.onComplete(x -> {
    if (x.failed()) {
      logger.error(x.cause().getMessage());
    }
    if (initMode != InitMode.NORMAL) {
      vertx.close();
    }
    promise.handle(x);
  });
}
 
Example 3
Source File: RegistrationServiceTests.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Assert devices, expecting them to be "not found".
 *
 * @param devices The map of devices to assert.
 * @return A future, reporting the assertion status.
 */
protected Future<?> assertDevicesNotFound(final Map<String, Device> devices) {

    Future<?> current = Future.succeededFuture();

    for (final Map.Entry<String, Device> entry : devices.entrySet()) {
        current = current.compose(ok -> assertDevice(TENANT, entry.getKey(), Optional.empty(),
                r -> {
                    assertThat(r.getStatus()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND);
                },
                r -> {
                    assertThat(r.getStatus()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND);
                }));
    }

    return current;

}
 
Example 4
Source File: ZookeeperLeaderFinder.java    From strimzi-kafka-operator with Apache License 2.0 6 votes vote down vote up
/**
 * Returns a Future which completes with the the id of the Zookeeper leader.
 * An exponential backoff is used if no ZK node is leader on the attempt to find it.
 * If there is no leader after 3 attempts then the returned Future completes with {@link #UNKNOWN_LEADER}.
 */
Future<Integer> findZookeeperLeader(String cluster, String namespace, List<Pod> pods, Secret coKeySecret) {
    if (pods.size() <= 1) {
        return Future.succeededFuture(pods.size() - 1);
    }
    String clusterCaSecretName = KafkaResources.clusterCaCertificateSecretName(cluster);
    Future<Secret> clusterCaKeySecretFuture = secretOperator.getAsync(namespace, clusterCaSecretName);
    return clusterCaKeySecretFuture.compose(clusterCaCertificateSecret -> {
        if (clusterCaCertificateSecret  == null) {
            return Future.failedFuture(Util.missingSecretException(namespace, clusterCaSecretName));
        }
        try {
            NetClientOptions netClientOptions = clientOptions(coKeySecret, clusterCaCertificateSecret);
            return zookeeperLeader(cluster, namespace, pods, netClientOptions);
        } catch (Throwable e) {
            return Future.failedFuture(e);
        }
    });

}
 
Example 5
Source File: RegistrationServiceTests.java    From hono with Eclipse Public License 2.0 6 votes vote down vote up
/**
 * Creates a set of devices.
 *
 * @param devices The devices to create.
 * @return A succeeded future if all devices have been created successfully.
 */
protected Future<?> createDevices(final Map<String, Device> devices) {

    Future<?> current = Future.succeededFuture();
    for (final Map.Entry<String, Device> entry : devices.entrySet()) {

        current = current.compose(ok -> getDeviceManagementService()
                .createDevice(TENANT, Optional.of(entry.getKey()), entry.getValue(), NoopSpan.INSTANCE)
                .map(r -> {
                    assertThat(r.getStatus()).isEqualTo(HttpURLConnection.HTTP_CREATED);
                    return null;
                }));

    }

    return current;

}
 
Example 6
Source File: ShoppingCartServiceImpl.java    From vertx-blueprint-microservice with Apache License 2.0 6 votes vote down vote up
/**
 * Get the shopping cart for a certain user.
 *
 * @param userId user id
 * @return async result
 */
private Future<ShoppingCart> aggregateCartEvents(String userId) {
  Future<ShoppingCart> future = Future.future();
  // aggregate cart events into raw shopping cart
  repository.streamByUser(userId)
    .takeWhile(cartEvent -> !CartEvent.isTerminal(cartEvent.getCartEventType()))
    .reduce(new ShoppingCart(), ShoppingCart::incorporate)
    .toSingle()
    .subscribe(future::complete, future::fail);

  return future.compose(cart ->
    getProductService()
      .compose(service -> prepareProduct(service, cart)) // prepare product data
      .compose(productList -> generateCurrentCartFromStream(cart, productList)) // prepare product items
  );
}
 
Example 7
Source File: ZookeeperLeaderFinder.java    From strimzi-kafka-operator with Apache License 2.0 5 votes vote down vote up
/**
 * Synchronously find the leader by testing each pod in the given list
 * using {@link #isLeader(Pod, NetClientOptions)}.
 */
private Future<Integer> zookeeperLeader(List<Pod> pods, NetClientOptions netClientOptions) {
    try {
        Future<Integer> f = Future.succeededFuture(UNKNOWN_LEADER);
        for (int i = 0; i < pods.size(); i++) {
            final int podNum = i;
            Pod pod = pods.get(i);
            String podName = pod.getMetadata().getName();
            f = f.compose(leader -> {
                if (leader == UNKNOWN_LEADER) {
                    log.debug("Checker whether {} is leader", podName);
                    return isLeader(pod, netClientOptions).map(isLeader -> {
                        if (isLeader != null && isLeader) {
                            log.info("Pod {} is leader", podName);
                            return podNum;
                        } else {
                            log.info("Pod {} is not a leader", podName);
                            return UNKNOWN_LEADER;
                        }
                    });
                } else {
                    return Future.succeededFuture(leader);
                }
            });
        }
        return f;
    } catch (Throwable t) {
        return Future.failedFuture(t);
    }
}
 
Example 8
Source File: KafkaAvailability.java    From strimzi-kafka-operator with Apache License 2.0 5 votes vote down vote up
KafkaAvailability(Admin ac) {
    this.ac = ac;
    // 1. Get all topic names
    Future<Set<String>> topicNames = topicNames();
    // 2. Get topic descriptions
    descriptions = topicNames.compose(names -> {
        log.debug("Got {} topic names", names.size());
        log.trace("Topic names {}", names);
        return describeTopics(names);
    });
}
 
Example 9
Source File: CheckoutServiceImpl.java    From vertx-blueprint-microservice with Apache License 2.0 5 votes vote down vote up
/**
 * Save checkout cart event for current user.
 *
 * @param userId user id
 * @return async result
 */
private Future<Void> saveCheckoutEvent(String userId) {
  Future<ShoppingCartService> future = Future.future();
  EventBusService.getProxy(discovery, ShoppingCartService.class, future.completer());
  return future.compose(service -> {
    Future<Void> resFuture = Future.future();
    CartEvent event = CartEvent.createCheckoutEvent(userId);
    service.addCartEvent(event, resFuture.completer());
    return resFuture;
  });
}
 
Example 10
Source File: KafkaAvailability.java    From strimzi-kafka-operator with Apache License 2.0 5 votes vote down vote up
private Future<Boolean> canRollBroker(Future<Collection<TopicDescription>> descriptions, int podId) {
    Future<Set<TopicDescription>> topicsOnGivenBroker = descriptions
            .compose(topicDescriptions -> {
                log.debug("Got {} topic descriptions", topicDescriptions.size());
                return Future.succeededFuture(groupTopicsByBroker(topicDescriptions, podId));
            }).recover(error -> {
                log.warn(error);
                return Future.failedFuture(error);
            });

    // 4. Get topic configs (for those on $broker)
    Future<Map<String, Config>> topicConfigsOnGivenBroker = topicsOnGivenBroker
            .compose(td -> topicConfigs(td.stream().map(t -> t.name()).collect(Collectors.toSet())));

    // 5. join
    return topicConfigsOnGivenBroker.map(topicNameToConfig -> {
        Collection<TopicDescription> tds = topicsOnGivenBroker.result();
        boolean canRoll = tds.stream().noneMatch(
            td -> wouldAffectAvailability(podId, topicNameToConfig, td));
        if (!canRoll) {
            log.debug("Restart pod {} would remove it from ISR, stalling producers with acks=all", podId);
        }
        return canRoll;
    }).recover(error -> {
        log.warn("Error determining whether it is safe to restart pod {}", podId, error);
        return Future.failedFuture(error);
    });
}
 
Example 11
Source File: CheckoutServiceImpl.java    From vertx-blueprint-microservice with Apache License 2.0 5 votes vote down vote up
@Override
public void checkout(String userId, Handler<AsyncResult<CheckoutResult>> resultHandler) {
  if (userId == null) {
    resultHandler.handle(Future.failedFuture(new IllegalStateException("Invalid user")));
    return;
  }
  Future<ShoppingCart> cartFuture = getCurrentCart(userId);
  Future<CheckoutResult> orderFuture = cartFuture.compose(cart ->
    checkAvailableInventory(cart).compose(checkResult -> {
      if (checkResult.getBoolean("res")) {
        double totalPrice = calculateTotalPrice(cart);
        // create order instance
        Order order = new Order().setBuyerId(userId)
          .setPayId("TEST") // reserved field
          .setProducts(cart.getProductItems())
          .setTotalPrice(totalPrice);
        // set id and then send order, wait for reply
        return retrieveCounter("order")
          .compose(id -> sendOrderAwaitResult(order.setOrderId(id)))
          .compose(result -> saveCheckoutEvent(userId).map(v -> result));
      } else {
        // has insufficient inventory, fail
        return Future.succeededFuture(new CheckoutResult()
          .setMessage(checkResult.getString("message")));
      }
    })
  );

  orderFuture.setHandler(resultHandler);
}
 
Example 12
Source File: MockCruiseControlTest.java    From strimzi-kafka-operator with Apache License 2.0 5 votes vote down vote up
private void runTest(Vertx vertx, VertxTestContext context, String userTaskID, int pendingCalls) throws IOException, URISyntaxException {

        MockCruiseControl.setupCCUserTasksResponseNoGoals(ccServer, 0, pendingCalls);

        CruiseControlApi client = new CruiseControlApiImpl(vertx);

        Future<CruiseControlResponse> statusFuture = client.getUserTaskStatus(HOST, PORT, userTaskID);

        Checkpoint checkpoint = context.checkpoint(pendingCalls + 1);

        for (int i = 1; i <= pendingCalls; i++) {
            statusFuture = statusFuture.compose(response -> {
                context.verify(() -> assertThat(
                        response.getJson().getString("Status"),
                        is(CruiseControlUserTaskStatus.IN_EXECUTION.toString()))
                );
                checkpoint.flag();
                return client.getUserTaskStatus(HOST, PORT, userTaskID);
            });
        }

        statusFuture.compose(response -> {
            context.verify(() -> assertThat(
                    response.getJson().getString("Status"),
                    is(CruiseControlUserTaskStatus.COMPLETED.toString()))
            );
            checkpoint.flag();
            return Future.succeededFuture(response);
        });
    }
 
Example 13
Source File: Job.java    From vertx-kue with Apache License 2.0 5 votes vote down vote up
/**
 * Save the job to the backend.
 */
public Future<Job> save() {
  // check
  Objects.requireNonNull(this.type, "Job type cannot be null");

  if (this.id > 0)
    return update();

  Future<Job> future = Future.future();

  // generate id
  client.incr(RedisHelper.getKey("ids"), res -> {
    if (res.succeeded()) {
      this.id = res.result();
      this.zid = RedisHelper.createFIFO(id);
      String key = RedisHelper.getKey("job:" + this.id);
      // need subscribe
      if (this.delay > 0) {
        this.state = JobState.DELAYED;
      }
      client.sadd(RedisHelper.getKey("job:types"), this.type, _failure());
      this.created_at = System.currentTimeMillis();
      this.promote_at = this.created_at + this.delay;
      // save job
      client.hmset(key, this.toJson(), _completer(future, this));
    } else {
      future.fail(res.cause());
    }
  });

  return future.compose(Job::update);
}
 
Example 14
Source File: AbstractVertxBasedMqttProtocolAdapter.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
private Future<Device> handleEndpointConnectionWithAuthentication(final MqttEndpoint endpoint,
        final Span currentSpan) {

    final MqttContext context = MqttContext.fromConnectPacket(endpoint);
    final Future<OptionalInt> traceSamplingPriority = applyTenantTraceSamplingPriority(context, currentSpan);
    final Future<DeviceUser> authAttempt = traceSamplingPriority.compose(v -> {
        context.setTracingContext(currentSpan.context());
        return authenticate(context);
    });
    return authAttempt
            .compose(authenticatedDevice -> CompositeFuture.all(
                    getTenantConfiguration(authenticatedDevice.getTenantId(), currentSpan.context())
                        .compose(tenantObj -> CompositeFuture.all(
                                isAdapterEnabled(tenantObj),
                                checkConnectionLimit(tenantObj, currentSpan.context()))),
                    checkDeviceRegistration(authenticatedDevice, currentSpan.context()))
                    .map(ok -> authenticatedDevice))
            .compose(authenticatedDevice -> createLinks(authenticatedDevice, currentSpan))
            .compose(authenticatedDevice -> registerHandlers(endpoint, authenticatedDevice, traceSamplingPriority.result()))
            .recover(t -> {
                if (authAttempt.failed()) {
                    log.debug("could not authenticate device", t);
                } else {
                    log.debug("cannot establish connection with device [tenant-id: {}, device-id: {}]",
                            authAttempt.result().getTenantId(), authAttempt.result().getDeviceId(), t);
                }
                return Future.failedFuture(t);
            });
}
 
Example 15
Source File: RegistrationServiceTests.java    From hono with Eclipse Public License 2.0 5 votes vote down vote up
/**
 * Assert a set of devices.
 * <p>
 * This will read the devices and expect them to be found and match the provided device information.
 *
 * @param devices The devices and device information.
 * @return A future, reporting the assertion status.
 */
protected Future<?> assertDevices(final Map<String, Device> devices) {

    Future<?> current = Future.succeededFuture();

    for (final Map.Entry<String, Device> entry : devices.entrySet()) {
        final var device = entry.getValue();
        current = current.compose(ok -> assertDevice(TENANT, entry.getKey(), Optional.empty(),
                r -> {
                    assertThat(r.isOk());
                    assertThat(r.getPayload()).isNotNull();
                    assertThat(r.getResourceVersion()).isNotNull(); // may be empty, but not null
                    assertThat(r.getCacheDirective()).isNotNull(); // may be empty, but not null
                    assertThat(r.getPayload().isEnabled()).isEqualTo(device.isEnabled());
                    assertThat(r.getPayload().getVia()).isEqualTo(device.getVia());
                },
                r -> {
                    if (device.isEnabled()) {
                        assertThat(r.isOk());
                        assertThat(r.getPayload()).isNotNull();
                        final JsonArray actualVias = r.getPayload().getJsonArray(RegistryManagementConstants.FIELD_VIA, new JsonArray());
                        assertThat(actualVias).hasSameElementsAs(device.getVia());
                    } else {
                        assertThat(r.getStatus()).isEqualTo(HttpURLConnection.HTTP_NOT_FOUND);
                        assertThat(r.getPayload()).isNull();
                    }
                }));
    }

    return current;

}
 
Example 16
Source File: TenantLoading.java    From raml-module-builder with Apache License 2.0 5 votes vote down vote up
private static void loadData(String okapiUrl, Map<String, String> headers,
  LoadingEntry loadingEntry, HttpClient httpClient,
  Handler<AsyncResult<Integer>> res) {

  String filePath = loadingEntry.lead;
  if (!loadingEntry.filePath.isEmpty()) {
    filePath = filePath + '/' + loadingEntry.filePath;
  }
  final String endPointUrl = okapiUrl + "/" + loadingEntry.uriPath;
  try {
    List<URL> urls = getURLsFromClassPathDir(filePath);
    if (urls.isEmpty()) {
      log.warn("loadData getURLsFromClassPathDir returns empty list for path=" + filePath);
    }
    Future<Void> future = Future.succeededFuture();
    for (URL url : urls) {
      future = future.compose(x -> {
        Promise<Void> p = Promise.promise();
        loadURL(headers, url, httpClient, loadingEntry, endPointUrl, p.future());
        return p.future();
      });
    }
    future.onComplete(x -> {
      if (x.failed()) {
        res.handle(Future.failedFuture(x.cause().getLocalizedMessage()));
      } else {
        res.handle(Future.succeededFuture(urls.size()));
      }
    });
  } catch (URISyntaxException|IOException ex) {
    log.error("Exception for path " + filePath, ex);
    res.handle(Future.failedFuture("Exception for path " + filePath + " ex=" + ex.getMessage()));
  }
}
 
Example 17
Source File: Job.java    From vertx-kue with Apache License 2.0 4 votes vote down vote up
/**
 * Log with some messages.
 */
public Future<Job> log(String msg) {
  Future<Job> future = Future.future();
  client.rpush(RedisHelper.getKey("job:" + this.id + ":log"), msg, _completer(future, this));
  return future.compose(Job::updateNow);
}
 
Example 18
Source File: Job.java    From vertx-kue with Apache License 2.0 4 votes vote down vote up
/**
 * Set new job state.
 *
 * @param newState new job state
 * @return async result of this job
 */
public Future<Job> state(JobState newState) {
  Future<Job> future = Future.future();
  RedisClient client = RedisHelper.client(vertx, new JsonObject()); // use a new client to keep transaction
  JobState oldState = this.state;
  logger.debug("Job::state(from: " + oldState + ", to:" + newState.name() + ")");
  client.transaction().multi(r0 -> {
    if (r0.succeeded()) {
      if (oldState != null && !oldState.equals(newState)) {
        client.transaction().zrem(RedisHelper.getStateKey(oldState), this.zid, _failure())
          .zrem(RedisHelper.getKey("jobs:" + this.type + ":" + oldState.name()), this.zid, _failure());
      }
      client.transaction().hset(RedisHelper.getKey("job:" + this.id), "state", newState.name(), _failure())
        .zadd(RedisHelper.getKey("jobs:" + newState.name()), this.priority.getValue(), this.zid, _failure())
        .zadd(RedisHelper.getKey("jobs:" + this.type + ":" + newState.name()), this.priority.getValue(), this.zid, _failure());

      switch (newState) { // dispatch different state
        case ACTIVE:
          client.transaction().zadd(RedisHelper.getKey("jobs:" + newState.name()),
            this.priority.getValue() < 0 ? this.priority.getValue() : -this.priority.getValue(),
            this.zid, _failure());
          break;
        case DELAYED:
          client.transaction().zadd(RedisHelper.getKey("jobs:" + newState.name()),
            this.promote_at, this.zid, _failure());
          break;
        case INACTIVE:
          client.transaction().lpush(RedisHelper.getKey(this.type + ":jobs"), "1", _failure());
          break;
        default:
      }

      this.state = newState;

      client.transaction().exec(r -> {
        if (r.succeeded()) {
          future.complete(this);
        } else {
          future.fail(r.cause());
        }
      });
    } else {
      future.fail(r0.cause());
    }
  });

  return future.compose(Job::updateNow);
}
 
Example 19
Source File: VertxBasedAmqpProtocolAdapter.java    From hono with Eclipse Public License 2.0 4 votes vote down vote up
private Future<ProtonDelivery> doUploadMessage(
        final AmqpContext context,
        final ResourceIdentifier resource,
        final Future<DownstreamSender> senderFuture,
        final Span currentSpan) {

    log.trace("forwarding {} message", context.getEndpoint().getCanonicalName());

    final Future<JsonObject> tokenFuture = getRegistrationAssertion(resource.getTenantId(), resource.getResourceId(),
            context.getAuthenticatedDevice(), currentSpan.context());
    final Future<TenantObject> tenantTracker = getTenantConfiguration(resource.getTenantId(),
            currentSpan.context());
    final Future<TenantObject> tenantValidationTracker = tenantTracker
            .compose(tenantObject -> CompositeFuture
                    .all(isAdapterEnabled(tenantObject),
                            checkMessageLimit(tenantObject, context.getPayloadSize(), currentSpan.context()))
                    .map(success -> tenantObject));

    return CompositeFuture.all(tenantValidationTracker, tokenFuture, senderFuture)
            .compose(ok -> {

                final DownstreamSender sender = senderFuture.result();
                final Message downstreamMessage = addProperties(
                        context.getMessage(),
                        ResourceIdentifier.from(context.getEndpoint().getCanonicalName(), resource.getTenantId(), resource.getResourceId()),
                        context.getAddress().toString(),
                        tenantValidationTracker.result(),
                        tokenFuture.result(),
                        null); // no TTD

                if (context.isRemotelySettled()) {
                    // client uses AT_MOST_ONCE delivery semantics -> fire and forget
                    return sender.send(downstreamMessage, currentSpan.context());
                } else {
                    // client uses AT_LEAST_ONCE delivery semantics
                    return sender.sendAndWaitForOutcome(downstreamMessage, currentSpan.context());
                }

            }).recover(t -> {

                log.debug("cannot process {} message from device [tenant: {}, device-id: {}]",
                        context.getEndpoint().getCanonicalName(),
                        resource.getTenantId(),
                        resource.getResourceId(), t);
                metrics.reportTelemetry(
                        context.getEndpoint(),
                        resource.getTenantId(),
                        tenantTracker.result(),
                        ProcessingOutcome.from(t),
                        context.isRemotelySettled() ? QoS.AT_MOST_ONCE : QoS.AT_LEAST_ONCE,
                        context.getPayloadSize(),
                        context.getTimer());
                return Future.failedFuture(t);

            }).map(delivery -> {

                metrics.reportTelemetry(
                        context.getEndpoint(),
                        resource.getTenantId(),
                        tenantTracker.result(),
                        ProcessingOutcome.FORWARDED,
                        context.isRemotelySettled() ? QoS.AT_MOST_ONCE : QoS.AT_LEAST_ONCE,
                        context.getPayloadSize(),
                        context.getTimer());
                return delivery;
            });
}
 
Example 20
Source File: KafkaAssemblyOperator.java    From strimzi-kafka-operator with Apache License 2.0 4 votes vote down vote up
/**
 * Internal method for checking Pods and PVCs for deletion. It goes through the pods and checks the annotations
 * to decide whether they should be deleted. For the first pod marked to be deleted, it will gather the existing
 * and desired PVCs to be able to delete and recreate them.
 *
 * This method exits with the first Pod it finds where deletion is required. The deletion is done asynchronously
 * so if we deleted multiple pods at the same time we would either need to sync the deletions of different pods
 * to not happen in parallel or have a risk that there will be several pods deleted at the same time (which can
 * affect availability). If multiple pods are marked for deletion, the next one will be deleted in the next loop.
 *
 * @param stsOperator           StatefulSet Operator for managing stateful sets
 * @param sts                   StatefulSet which owns the pods which should be checked for deletion
 * @param desiredPvcs           The list of PVCs which should exist
 * @param existingPvcsFuture    Future which will return a list of PVCs which actually exist
 * @return
 */
@SuppressWarnings("deprecation")
Future<Void> maybeCleanPodAndPvc(StatefulSetOperator stsOperator, StatefulSet sts, List<PersistentVolumeClaim> desiredPvcs, Future<List<PersistentVolumeClaim>> existingPvcsFuture)  {
    if (sts != null) {
        log.debug("{}: Considering manual cleaning of Pods for StatefulSet {}", reconciliation, sts.getMetadata().getName());

        String stsName = sts.getMetadata().getName();

        for (int i = 0; i < sts.getSpec().getReplicas(); i++) {
            String podName = stsName + "-" + i;
            Pod pod = podOperations.get(namespace, podName);

            if (pod != null) {
                if (Annotations.booleanAnnotation(pod, AbstractScalableResourceOperator.ANNO_STRIMZI_IO_DELETE_POD_AND_PVC,
                        false, AbstractScalableResourceOperator.ANNO_OP_STRIMZI_IO_DELETE_POD_AND_PVC)) {
                    log.debug("{}: Pod and PVCs for {} should be deleted based on annotation", reconciliation, podName);

                    return existingPvcsFuture
                            .compose(existingPvcs -> {
                                List<PersistentVolumeClaim> deletePvcs;

                                if (existingPvcs != null) {
                                    deletePvcs = existingPvcs
                                            .stream()
                                            .filter(pvc -> pvc.getMetadata().getName().endsWith(podName))
                                            .collect(Collectors.toList());
                                } else {
                                    deletePvcs = new ArrayList<>(0);
                                }

                                List<PersistentVolumeClaim> createPvcs = desiredPvcs
                                        .stream()
                                        .filter(pvc -> pvc.getMetadata().getName().endsWith(podName))
                                        .collect(Collectors.toList());

                                return cleanPodAndPvc(stsOperator, sts, podName, deletePvcs, createPvcs);
                            });
                }
            }
        }
    }

    return Future.succeededFuture();
}